<?php
/**
 * MyBB 1.8
 * Copyright 2014 MyBB Group, All Rights Reserved
 *
 * Website: http://www.mybb.com
 * License: http://www.mybb.com/about/license
 *
 */

// Disallow direct access to this file for security reasons
if(!defined("IN_MYBB"))
{
	die("Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.");
}

/**
 * Used to execute a custom moderation tool
 *
 */

class CustomModeration extends Moderation
{
	/**
	 * Get info on a tool
	 *
	 * @param int Tool ID
	 * @param mixed Thread IDs
	 * @param mixed Post IDs
	 * @return mixed Returns tool data (tid, type, name, description) in an array, otherwise boolean false.
	 */
	function tool_info($tool_id)
	{
		global $db;

		// Get tool info
		$query = $db->simple_select("modtools", "*", 'tid="'.(int)$tool_id.'"');
		$tool = $db->fetch_array($query);
		if(!$tool['tid'])
		{
			return false;
		}
		else
		{
			return $tool;
		}
	}

	/**
	 * Execute Custom Moderation Tool
	 *
	 * @param int Tool ID
	 * @param mixed Thread ID(s)
	 * @param mixed Post IDs
	 * @return string 'forum' or 'default' indicating where to redirect
	 */
	function execute($tool_id, $tids=0, $pids=0)
	{
		global $db;

		// Get tool info
		$query = $db->simple_select("modtools", '*', 'tid="'.(int)$tool_id.'"');
		$tool = $db->fetch_array($query);
		if(!$tool['tid'])
		{
			return false;
		}

		// Format single tid and pid
		if(!is_array($tids))
		{
			$tids = array($tids);
		}
		if(!is_array($pids))
		{
			$pids = array($pids);
		}

		// Unserialize custom moderation
		$post_options = my_unserialize($tool['postoptions']);
		$thread_options = my_unserialize($tool['threadoptions']);

		// If the tool type is a post tool, then execute the post moderation
		if($tool['type'] == 'p')
		{
			$deleted_thread = $this->execute_post_moderation($post_options, $pids, $tids);
		}
		// Always execute thead moderation
		$this->execute_thread_moderation($thread_options, $tids);

		// If the thread is deleted, indicate to the calling script to redirect to the forum, and not the nonexistant thread
		if($thread_options['deletethread'] == 1 || $deleted_thread === 1)
		{
			return 'forum';
		}
		return 'default';
	}

	/**
	 * Execute Inline Post Moderation
	 *
	 * @param array Moderation information
	 * @param mixed Post IDs
	 * @param array Thread IDs (in order of dateline ascending)
	 * @return boolean true
	 */
	function execute_post_moderation($post_options, $pids, $tid)
	{
		global $db, $mybb, $lang;

		if(is_array($tid))
		{
			$tid = (int)$tid[0]; // There's only 1 thread when doing inline post moderation
			// The thread chosen is the first thread in the array of tids.
			// It is recommended that this be the tid of the oldest post
		}

		// Get the information about thread
		$thread = get_thread($tid);

		// If deleting posts, only do that
		if($post_options['deleteposts'] == 1)
		{
			foreach($pids as $pid)
			{
				$this->delete_post($pid);
			}

			$delete_tids = array();
			$imploded_pids = implode(",", array_map("intval", $pids));
			$query = $db->simple_select("threads", "tid", "firstpost IN ({$imploded_pids})");
			while($threadid = $db->fetch_field($query, "tid"))
			{
				$delete_tids[] = $threadid;
			}
			if(!empty($delete_tids))
			{
				foreach($delete_tids as $delete_tid)
				{
					$this->delete_thread($delete_tid);
					mark_reports($delete_tid, "thread");
				}
				// return 1 here so the code in execute() above knows to redirect to the forum
				return 1;
			}
		}
		else
		{
			if($post_options['mergeposts'] == 1) // Merge posts
			{
				$this->merge_posts($pids);
			}

			if($post_options['approveposts'] == 'approve') // Approve posts
			{
				$this->approve_posts($pids);
			}
			elseif($post_options['approveposts'] == 'unapprove') // Unapprove posts
			{
				$this->unapprove_posts($pids);
			}
			elseif($post_options['approveposts'] == 'toggle') // Toggle post visibility
			{
				$this->toggle_post_visibility($pids);
			}

			if($post_options['softdelete'] == 'softdelete') // Soft delete posts
			{
				$this->soft_delete_posts($pids);
			}
			elseif($post_options['softdelete'] == 'restore') // Restore posts
			{
				$this->restore_posts($pids);
			}
			elseif($post_options['softdelete'] == 'toggle') // Toggle post visibility
			{
				$this->toggle_post_softdelete($pids);
			}

			if($post_options['splitposts'] > 0 || $post_options['splitposts'] == -2) // Split posts
			{
				$query = $db->simple_select("posts", "COUNT(*) AS totalposts", "tid='{$tid}'");
				$count = $db->fetch_array($query);

				if($count['totalposts'] == 1)
				{
					error($lang->error_cantsplitonepost);
				}

				if($count['totalposts'] == count($pids))
				{
					error($lang->error_cantsplitall);
				}

				if($post_options['splitposts'] == -2)
				{
					$post_options['splitposts'] = $thread['fid'];
				}
				if(empty($post_options['splitpostsnewsubject']))
				{
					// Enter in a subject if a predefined one does not exist.
					$post_options['splitpostsnewsubject'] = "{$lang->split_thread_subject} {$thread['subject']}";
				}
				$new_subject = str_ireplace('{subject}', $thread['subject'], $post_options['splitpostsnewsubject']);
				$new_tid = $this->split_posts($pids, $tid, $post_options['splitposts'], $new_subject);
				if($post_options['splitpostsclose'] == 'close') // Close new thread
				{
					$this->close_threads($new_tid);
				}
				if($post_options['splitpostsstick'] == 'stick') // Stick new thread
				{
					$this->stick_threads($new_tid);
				}
				if($post_options['splitpostsunapprove'] == 'unapprove') // Unapprove new thread
				{
					$this->unapprove_threads($new_tid, $thread['fid']);
				}
				if($post_options['splitthreadprefix'] != '0')
				{
					$this->apply_thread_prefix($new_tid, $post_options['splitthreadprefix']); // Add thread prefix to new thread
				}
				if(!empty($post_options['splitpostsaddreply'])) // Add reply to new thread
				{
					require_once MYBB_ROOT."inc/datahandlers/post.php";
					$posthandler = new PostDataHandler("insert");

					if(empty($post_options['splitpostsreplysubject']))
					{
						$post_options['splitpostsreplysubject'] = 'RE: '.$new_subject;
					}
					else
					{
						$post_options['splitpostsreplysubject'] = str_ireplace('{username}', $mybb->user['username'], $post_options['splitpostsreplysubject']);
						$post_options['splitpostsreplysubject'] = str_ireplace('{subject}', $new_subject, $post_options['splitpostsreplysubject']);
					}

					// Set the post data that came from the input to the $post array.
					$post = array(
						"tid" => $new_tid,
						"fid" => $post_options['splitposts'],
						"subject" => $post_options['splitpostsreplysubject'],
						"uid" => $mybb->user['uid'],
						"username" => $mybb->user['username'],
						"message" => $post_options['splitpostsaddreply'],
						"ipaddress" => $db->escape_binary(my_inet_pton(get_ip())),
					);
					// Set up the post options from the input.
					$post['options'] = array(
						"signature" => 1,
						"emailnotify" => 0,
						"disablesmilies" => 0
					);

					$posthandler->set_data($post);

					if($posthandler->validate_post($post))
					{
						$posthandler->insert_post($post);
					}
				}
			}
		}
		return true;
	}

	/**
	 * Execute Normal and Inline Thread Moderation
	 *
	 * @param array Moderation information
	 * @param mixed Thread IDs
	 * @return boolean true
	 */
	function execute_thread_moderation($thread_options, $tids)
	{
		global $db, $mybb;

		$tid = (int)$tids[0]; // Take the first thread to get thread data from
		$query = $db->simple_select("threads", 'fid', "tid='$tid'");
		$thread = $db->fetch_array($query);

		// If deleting threads, only do that
		if($thread_options['deletethread'] == 1)
		{
			foreach($tids as $tid)
			{
				$this->delete_thread($tid);
			}
		}
		else
		{
			if($thread_options['mergethreads'] == 1 && count($tids) > 1) // Merge Threads (ugly temp code until find better fix)
			{
				$tid_list = implode(',', $tids);
				$options = array('order_by' => 'dateline', 'order_dir' => 'DESC');
				$query = $db->simple_select("threads", 'tid, subject', "tid IN ($tid_list)", $options); // Select threads from newest to oldest
				$last_tid = 0;
				while($tid = $db->fetch_array($query))
				{
					if($last_tid != 0)
					{
						$this->merge_threads($last_tid, $tid['tid'], $tid['subject']); // And keep merging them until we get down to one thread.
					}
					$last_tid = $tid['tid'];
				}
			}
			if($thread_options['deletepoll'] == 1) // Delete poll
			{
				foreach($tids as $tid)
				{
					$this->delete_poll($tid);
				}
			}
			if($thread_options['removeredirects'] == 1) // Remove redirects
			{
				foreach($tids as $tid)
				{
					$this->remove_redirects($tid);
				}
			}

			if($thread_options['removesubscriptions'] == 1) // Remove thread subscriptions
			{
				$this->remove_thread_subscriptions($tids, true);
			}

			if($thread_options['approvethread'] == 'approve') // Approve thread
			{
				$this->approve_threads($tids, $thread['fid']);
			}
			elseif($thread_options['approvethread'] == 'unapprove') // Unapprove thread
			{
				$this->unapprove_threads($tids, $thread['fid']);
			}
			elseif($thread_options['approvethread'] == 'toggle') // Toggle thread visibility
			{
				$this->toggle_thread_visibility($tids, $thread['fid']);
			}

			if($thread_options['softdelete'] == 'softdelete') // Soft delete thread
			{
				$this->soft_delete_threads($tids, $thread['fid']);
			}
			elseif($thread_options['softdelete'] == 'restore') // Restore thread
			{
				$this->restore_threads($tids, $thread['fid']);
			}
			elseif($thread_options['softdelete'] == 'toggle') // Toggle thread visibility
			{
				$this->toggle_thread_softdelete($tids, $thread['fid']);
			}

			if($thread_options['openthread'] == 'open') // Open thread
			{
				$this->open_threads($tids);
			}
			elseif($thread_options['openthread'] == 'close') // Close thread
			{
				$this->close_threads($tids);
			}
			elseif($thread_options['openthread'] == 'toggle') // Toggle thread visibility
			{
				$this->toggle_thread_status($tids);
			}

			if($thread_options['stickthread'] == 'stick') // Stick thread
			{
				$this->stick_threads($tids);
			}
			elseif($thread_options['stickthread'] == 'unstick') // Unstick thread
			{
				$this->unstick_threads($tids);
			}
			elseif($thread_options['stickthread'] == 'toggle') // Toggle thread importance
			{
				$this->toggle_thread_importance($tids);
			}

			if($thread_options['threadprefix'] != '-1')
			{
				$this->apply_thread_prefix($tids, $thread_options['threadprefix']); // Update thread prefix
			}

			if(my_strtolower(trim($thread_options['newsubject'])) != '{subject}') // Update thread subjects
			{
				$this->change_thread_subject($tids, $thread_options['newsubject']);
			}
			if(!empty($thread_options['addreply'])) // Add reply to thread
			{
				$tid_list = implode(',', $tids);
				$query = $db->simple_select("threads", 'uid, fid, subject, tid, firstpost, closed', "tid IN ($tid_list) AND closed NOT LIKE 'moved|%'");
				require_once MYBB_ROOT."inc/datahandlers/post.php";

				// Loop threads adding a reply to each one
				while($thread = $db->fetch_array($query))
				{
					$posthandler = new PostDataHandler("insert");

					if(empty($thread_options['replysubject']))
                    {
                        $new_subject = 'RE: '.$thread['subject'];
                    }
                    else
                    {
                        $new_subject = str_ireplace('{username}', $mybb->user['username'], $thread_options['replysubject']);
                        $new_subject = str_ireplace('{subject}', $thread['subject'], $new_subject);
                    }

                    // Set the post data that came from the input to the $post array.
                    $post = array(
                        "tid" => $thread['tid'],
                        "replyto" => $thread['firstpost'],
                        "fid" => $thread['fid'],
                        "subject" => $new_subject,
						"uid" => $mybb->user['uid'],
						"username" => $mybb->user['username'],
						"message" => $thread_options['addreply'],
						"ipaddress" => $db->escape_binary(my_inet_pton(get_ip())),
					);

					// Set up the post options from the input.
					$post['options'] = array(
						"signature" => 1,
						"emailnotify" => 0,
						"disablesmilies" => 0
					);

					if($thread['closed'] == 1)
					{
						// Keep this thread closed
						$post['modoptions']['closethread'] = 1;
					}

					$posthandler->set_data($post);
					if($posthandler->validate_post($post))
					{
						$posthandler->insert_post($post);
					}
				}
			}
			if($thread_options['movethread'] > 0 && $thread_options['movethread'] != $thread['fid']) // Move thread
			{
				if($thread_options['movethreadredirect'] == 1) // Move Thread with redirect
				{
					$time = TIME_NOW + ($thread_options['movethreadredirectexpire'] * 86400);
					foreach($tids as $tid)
					{
						$this->move_thread($tid, $thread_options['movethread'], 'redirect', $time);
					}
				}
				else // Normal move
				{
					$this->move_threads($tids, $thread_options['movethread']);
				}
			}
			if($thread_options['copythread'] > 0 || $thread_options['copythread'] == -2) // Copy thread
			{
				if($thread_options['copythread'] == -2)
				{
					$thread_options['copythread'] = $thread['fid'];
				}
				foreach($tids as $tid)
				{
					$new_tid = $this->move_thread($tid, $thread_options['copythread'], 'copy');
				}
			}
			if(!empty($thread_options['recountrebuild']))
			{
				require_once MYBB_ROOT.'/inc/functions_rebuild.php';

				foreach($tids as $tid)
				{
					rebuild_thread_counters($tid);
				}
			}
		}
		
		// Do we have a PM subject and PM message?
		if(isset($thread_options['pm_subject']) && $thread_options['pm_subject'] != '' && isset($thread_options['pm_message']) && $thread_options['pm_message'] != '')
		{
			$tid_list = implode(',', $tids);
			
			// For each thread, we send a PM to the author
			$query = $db->simple_select("threads", 'uid', "tid IN ($tid_list)");
			while($uid = $db->fetch_field($query, 'uid'))
			{
				// Let's send our PM
				$pm = array(
					'subject' => $thread_options['pm_subject'],
					'message' => $thread_options['pm_message'],
					'touid' => $uid
				);
				send_pm($pm, $mybb->user['uid'], 1);
			}
		}
		
		return true;
	}
}
