AnonSec Shell
Server IP : 213.186.33.4  /  Your IP : 216.73.216.193
Web Server : Apache
System : Linux webm006.cluster103.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64
User : awebpaca ( 35430)
PHP Version : 8.5.0
Disable Function : _dyuweyrj4,_dyuweyrj4r,dl
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/awebpaca/blog/libraries/kunena/forum/message/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME ]     

Current File : /home/awebpaca/blog/libraries/kunena/forum/message/message.php
<?php
/**
 * Kunena Component
 * @package Kunena.Framework
 * @subpackage Forum.Message
 *
 * @copyright (C) 2008 - 2018 Kunena Team. All rights reserved.
 * @license https://www.gnu.org/copyleft/gpl.html GNU/GPL
 * @link https://www.kunena.org
 **/
defined ( '_JEXEC' ) or die ();

/**
 * Class KunenaForumMessage
 *
 * @property int $parent
 * @property int $thread
 * @property int $catid
 * @property string $name
 * @property int $userid
 * @property string $email
 * @property string $subject
 * @property int $time
 * @property string $ip
 * @property int $topic_emoticon
 * @property int $locked
 * @property int $hold
 * @property int $ordering
 * @property int $hits
 * @property int $moved
 * @property int $modified_by
 * @property string $modified_time
 * @property string $modified_reason
 * @property string $params
 * @property string $message
 */
class KunenaForumMessage extends KunenaDatabaseObject
{
	/**
	 * @var int
	 */
	public $id = null;

	protected $_table = 'KunenaMessages';
	protected $_db = null;
	/**
	 * @var KunenaAttachment[]
	 */
	protected $_attachments_add = array();
	/**
	 * @var KunenaAttachment[]
	 */
	protected $_attachments_del = array();
	protected $_topic = null;
	protected $_hold = 1;
	protected $_thread = 0;

	protected $_authcache = array();
	protected $_authtcache = array();
	protected $_authfcache = array();
	protected static $actions = array(
		'none'=>array(),
		'read'=>array('Read'),
		'reply'=>array('Read','NotHold'),
		'edit'=>array('Read','Own','EditTime'),
		'move'=>array('Read'),
		'approve'=>array('Read'),
		'delete'=>array('Read','Own', 'Delete'),
		'thankyou'=>array('Read', 'Thankyou'),
		'unthankyou'=>array('Read'),
		'undelete'=>array('Read'),
		'permdelete'=>array('Read', 'Permdelete'),
		'attachment.read'=>array('Read'),
		'attachment.createimage'=>array('Read','AttachmentsImage'),
		'attachment.createfile'=>array('Read','AttachmentsFile'),
		'attachment.delete'=>array(),
		// TODO: In the future we might want to restrict this: array('Read','EditTime'),
	);

	/**
	 * @param mixed $properties
	 *
	 * @internal
	 */
	public function __construct($properties = null)
	{
		$this->_db = JFactory::getDbo();
		parent::__construct($properties);
	}

	public function __destruct()
	{
		unset($this->_db);
		unset($this->_topic);
	}

	/**
	 * Returns KunenaForumMessage object.
	 *
	 * @param int $identifier	The message to load - Can be only an integer.
	 * @param bool $reload
	 *
	 * @return KunenaForumMessage
	 */
	static public function getInstance($identifier = null, $reload = false)
	{
		return KunenaForumMessageHelper::get($identifier, $reload);
	}

	/**
	 * @param mixed $user
	 *
	 * @return bool
	 */
	public function isNew($user = null)
	{
		$user = KunenaUserHelper::get($user);
		if (!KunenaFactory::getConfig()->shownew || !$user->exists())
		{
			return false;
		}

		$session = KunenaFactory::getSession ();

		if ($this->time < $session->getAllReadTime())
		{
			return false;
		}

		$allreadtime = KunenaForumCategoryUserHelper::get($this->getCategory(), $user)->allreadtime;

		if ($allreadtime && $this->time < $allreadtime)
		{
			return false;
		}

		$read = KunenaForumTopicUserReadHelper::get($this->getTopic(), $user);

		if ($this->id == $read->message_id || $this->time < $read->time) {
			return false;
		}

		return true;
	}

	/**
	 * Get published state in text.
	 *
	 * @return string
	 *
	 * @since  K4.0
	 */
	public function getState()
	{
		switch ($this->hold) {
			case 0:
				return 'published';
			case 1:
				return 'unapproved';
			case 2:
			case 3:
				return 'deleted';
		}

		return 'unknown';
	}

	/**
	 * @param null|KunenaForumCategory $category	Fake category if needed. Used for aliases.
	 * @param bool $xhtml
	 *
	 * @return string
	 */
	public function getUrl($category = null, $xhtml = true)
	{
		return $this->getTopic()->getUrl($category, $xhtml, $this);
	}

	/**
	 * @param null|KunenaForumCategory $category	Fake category if needed. Used for aliases.
	 *
	 * @return JUri
	 */
	public function getUri($category = null) {
		return $this->getTopic()->getUri($category, $this);
	}

	/**
	 *  Get permament topic URL without domain.
	 *
	 * If you want to add domain (for email etc), you can prepend the output with this:
	 * JUri::getInstance()->toString(array('scheme', 'host', 'port'))
	 *
	 * @param null|KunenaForumCategory $category	Fake category if needed. Used for aliases.
	 * @param bool $xhtml
	 *
	 * @return string
	 */
	public function getPermaUrl($category = null, $xhtml = true)
	{
		$uri = $this->getPermaUri($category);

		return KunenaRoute::_($uri, $xhtml);
	}

	/**
	 * @param null|KunenaForumCategory $category
	 *
	 * @return JUri
	 */
	public function getPermaUri($category = null)
	{
		$category = $category ? KunenaForumCategoryHelper::get($category) : $this->getCategory();

		if (!$this->exists() || !$category->exists())
		{
			return null;
		}

		$uri = JUri::getInstance("index.php?option=com_kunena&view=topic&catid={$category->id}&id={$this->thread}&mesid={$this->id}");

		return $uri;
	}

	/**
	 * @param array $fields
	 * @param mixed $user
	 * @param null|array  $safefields
	 *
	 * @return array
	 */
	public function newReply($fields = array(), $user = null, $safefields = null)
	{
		$user = KunenaUserHelper::get($user);
		$topic = $this->getTopic();
		$category = $this->getCategory();

		$message = new KunenaForumMessage();
		$message->setTopic($topic);
		$message->parent = $this->id;
		$message->thread = $topic->id;
		$message->catid = $topic->category_id;
		$message->name = $user->getName('');
		$message->userid = $user->userid;
		$message->subject = $this->subject;
		$message->ip = $_SERVER ["REMOTE_ADDR"];

		// Add IP to user.
		if (empty($user->ip))
		{
			$user->ip = $_SERVER ["REMOTE_ADDR"];
		}

		if ($topic->hold)
		{
			// If topic was unapproved or deleted, use the same state for the new message
			$message->hold = $topic->hold;
		}
		else
		{
			// Otherwise message is either unapproved or published depending if the category is moderated or not
			$message->hold = $category->review ? (int)!$category->authorise ('moderate', $user, true) : 0;
		}

		if ($fields === true)
		{
			$user = KunenaFactory::getUser($this->userid);
			$find = array('/\[hide\](.*?)\[\/hide\]/su', '/\[confidential\](.*?)\[\/confidential\]/su');
			$replace = '';
			$text = preg_replace($find, $replace, $this->message);
			$message->message = "[quote=\"{$user->getName($this->name)}\" post={$this->id}]" .  $text . "[/quote]";
		}
		else
		{
			if (is_array($safefields))
			{
				$message->bind($safefields);
			}

			if (is_array($fields))
			{
				$message->bind($fields, array ('name', 'email', 'subject', 'message' ), true);
			}
		}

		return array($topic, $message);
	}

	/**
	 * Send email notifications from the message.
	 *
	 * @param null|string $url
	 *
	 * @return bool|null
	 */
	public function sendNotification($url = null)
	{
		$config = KunenaFactory::getConfig();

		if (!$config->get('send_emails'))
		{
			return null;
		}

		if ($this->hold > 1)
		{
			return null;
		}
		elseif ($this->hold == 1)
		{
			$mailsubs = 0;
			$mailmods = $config->mailmod >= 0;
			$mailadmins = $config->mailadmin >= 0;
		}
		else
		{
			$mailsubs = (bool) $config->allowsubscriptions;
			$mailmods = $config->mailmod >= 1;
			$mailadmins = $config->mailadmin >= 1;
		}

		$once = false;

		if ($mailsubs)
		{
			if (!$this->parent)
			{
				// New topic: Send email only to category subscribers
				$mailsubs = $config->category_subscriptions != 'disabled' ? KunenaAccess::CATEGORY_SUBSCRIPTION : 0;
				$once = $config->category_subscriptions == 'topic';
			}
			elseif ($config->category_subscriptions != 'post')
			{
				// Existing topic: Send email only to topic subscribers
				$mailsubs = $config->topic_subscriptions != 'disabled' ? KunenaAccess::TOPIC_SUBSCRIPTION : 0;
				$once = $config->topic_subscriptions == 'first';
			}
			else
			{
				// Existing topic: Send email to both category and topic subscribers
				$mailsubs = $config->topic_subscriptions == 'disabled'
					? KunenaAccess::CATEGORY_SUBSCRIPTION
					: KunenaAccess::CATEGORY_SUBSCRIPTION | KunenaAccess::TOPIC_SUBSCRIPTION;
				// FIXME: category subscription can override topic
				$once = $config->topic_subscriptions == 'first';
			}
		}

		if (!$url)
		{
			$url = JUri::getInstance()->toString(array('scheme', 'host', 'port')) . $this->getPermaUrl();
		}

		// Get all subscribers, moderators and admins who should get the email.
		$emailToList = KunenaAccess::getInstance()->getSubscribers(
			$this->catid,
			$this->thread,
			$mailsubs,
			$mailmods,
			$mailadmins,
			KunenaUserHelper::getMyself()->userid
		);

		if ($emailToList)
		{
			if (!$config->getEmail())
			{
				KunenaError::warning(JText::_('COM_KUNENA_EMAIL_DISABLED'));

				return false;
			}
			elseif (!JMailHelper::isEmailAddress($config->getEmail()))
			{
				KunenaError::warning(JText::_('COM_KUNENA_EMAIL_INVALID'));

				return false;
			}

			$topic = $this->getTopic();

			// Make a list from all receivers; split the receivers into two distinct groups.
			$sentusers = array();
			$receivers = array(0 => array(), 1 => array());

			foreach($emailToList as $emailTo)
			{
				if (!$emailTo->email || !JMailHelper::isEmailAddress($emailTo->email))
				{
					continue;
				}

				$receivers[$emailTo->subscription][] = $emailTo->email;
				$sentusers[] = $emailTo->id;
			}

			$mailsender = JMailHelper::cleanAddress($config->board_title);
			$mailsubject = JMailHelper::cleanSubject ( $topic->subject . " (" . $this->getCategory()->name . ")" );
			$subject = $this->subject ? $this->subject : $topic->subject;

			// Create email.
			$mail = JFactory::getMailer();
			$mail->setSubject($mailsubject);
			$mail->setSender(array($config->getEmail(), $mailsender));

			// Send email to all subscribers.
			if (!empty($receivers[1]))
			{
				$this->attachEmailBody($mail, 1, $subject, $url, $once);
				KunenaEmail::send($mail, $receivers[1]);
			}

			// Send email to all moderators.
			if (!empty($receivers[0]))
			{
				$this->attachEmailBody($mail, 0, $subject, $url, $once);
				KunenaEmail::send($mail, $receivers[0]);
			}

			// Update subscriptions.
			if ($once && $sentusers)
			{
				$sentusers = implode (',', $sentusers);
				$db = JFactory::getDbo();
				$query = $db->getQuery(true)
					->update('#__kunena_user_topics')
					->set('subscribed=2')
					->where("topic_id={$this->thread}")
					->where("user_id IN ({$sentusers})")
					->where('subscribed=1');

				$db->setQuery($query);

				try
				{
					$db->execute();
				}
				catch (JDatabaseExceptionExecuting $e)
				{
					KunenaError::displayDatabaseError($e);
				}
			}
		}

		return true;
	}

	/**
	 * @param int $value
	 *
	 * @return bool
	 */
	public function publish($value=KunenaForum::PUBLISHED)
	{
		if ($this->hold == $value)
		{
			return true;
		}

		$this->hold = (int)$value;
		$result = $this->save();

		return $result;
	}

	/**
	 * @return KunenaForumTopic
	 */
	public function getTopic()
	{
		if (!$this->_topic)
		{
			$this->_topic = KunenaForumTopicHelper::get($this->thread);
		}

		return $this->_topic;
	}

	/**
	 * @param KunenaForumTopic $topic
	 */
	public function setTopic(KunenaForumTopic $topic)
	{
		$this->_topic = $topic;

		if ($topic->id)
		{
			$this->thread = $topic->id;
		}
	}

	/**
	 * @param mixed $user
	 *
	 * @return KunenaForumTopicUser
	 */
	public function getUserTopic($user = null)
	{
		return $this->getTopic()->getUserTopic($user);
	}

	/**
	 * @return KunenaForumMessageThankyou
	 */
	public function getThankyou()
	{
		return KunenaForumMessageThankyouHelper::get($this->id);
	}

	/**
	 * @return KunenaForumCategory
	 */
	public function getCategory()
	{
		return KunenaForumCategoryHelper::get($this->catid);
	}

	/**
	 * @return KunenaForumMessage
	 */
	public function getParent()
	{
		return KunenaForumMessageHelper::get($this->parent);
	}

	/**
	 * @return KunenaUser
	 */
	public function getAuthor()
	{
		return KunenaUserHelper::getAuthor($this->userid, $this->name);
	}

	/**
	 * @return KunenaDate
	 */
	public function getTime()
	{
		return new KunenaDate($this->time);
	}

	/**
	 * @return KunenaUser
	 */
	public function getModifier()
	{
		return KunenaUserHelper::get($this->modified_by);
	}

	/**
	 * @return KunenaDate
	 */
	public function getModifiedTime()
	{
		return new KunenaDate($this->modified_time);
	}

	/**
	 * Display required field from message table
	 *
	 * @param string $field
	 * @param boolean $html
	 * @param string $context
	 *
	 * @return int|string
	 */
	public function displayField($field, $html = true, $context = '')
	{
		switch ($field)
		{
			case 'id':
				return intval($this->id);
			case 'subject':
				return KunenaHtmlParser::parseText($this->subject);
			case 'message':
				return $html ? KunenaHtmlParser::parseBBCode($this->message, $this, 0, $context) : KunenaHtmlParser::stripBBCode
					($this->message, 0, $html);
		}

		return '';
	}

	/**
	 * Returns true if user is authorised to do the action.
	 *
	 * @param string     $action
	 * @param KunenaUser $user
	 *
	 * @return bool
	 *
	 * @since  K4.0
	 */
	public function isAuthorised($action='read', KunenaUser $user = null)
	{
		if (KunenaFactory::getConfig()->read_only)
		{
			// Special case to ignore authorisation.
			if ($action != 'read')
			{
				return null;
			}
		}

		return !$this->tryAuthorise($action, $user, false);
	}

	/**
	 * Throws an exception if user isn't authorised to do the action.
	 *
	 * @param string      $action
	 * @param KunenaUser  $user
	 * @param bool        $throw
	 *
	 * @return KunenaExceptionAuthorise|null
	 * @throws KunenaExceptionAuthorise
	 * @throws InvalidArgumentException
	 *
	 * @since  K4.0
	 */
	public function tryAuthorise($action='read', KunenaUser $user = null, $throw = true)
	{
		// Special case to ignore authorisation.
		if ($action == 'none')
		{
			return null;
		}

		// Load user if not given.
		if ($user === null)
		{
			$user = KunenaUserHelper::getMyself();
		}

		if (empty($this->_authcache[$user->userid][$action]))
		{
			// Unknown action - throw invalid argument exception.
			if (!isset(self::$actions[$action]))
			{
				throw new InvalidArgumentException(JText::sprintf('COM_KUNENA_LIB_AUTHORISE_INVALID_ACTION', $action), 500);
			}

			// Load category authorisation.
			if (!isset($this->_authtcache[$user->userid][$action]))
			{
				$this->_authtcache[$user->userid][$action] = $this->getTopic()->tryAuthorise('post.'.$action, $user, false);
			}

			$this->_authcache[$user->userid][$action] = $this->_authtcache[$user->userid][$action];

			if (empty($this->_authcache[$user->userid][$action]))
			{
				foreach (self::$actions[$action] as $function)
				{
					if (!isset($this->_authfcache[$user->userid][$function]))
					{
						$authFunction = 'authorise'.$function;
						$this->_authfcache[$user->userid][$function] = $this->$authFunction($user);
					}

					$error = $this->_authfcache[$user->userid][$function];

					if ($error)
					{
						$this->_authcache[$user->userid][$action] = $error;
						break;
					}
				}
			}
		}
		$exception = $this->_authcache[$user->userid][$action];

		// Throw or return the exception.
		if ($throw && $exception)
		{
			throw $exception;
		}

		return $exception;
	}

	 /**
	 * @param string $action
	 * @param mixed  $user
	 * @param bool   $silent
	 *
	 * @return bool
	 * @deprecated K4.0
	 */
	public function authorise($action = 'read', $user = null, $silent = false)
	{
		KUNENA_PROFILER ? KunenaProfiler::instance()->start('function '.__CLASS__.'::'.__FUNCTION__.'()') : null;

		if ($user === null)
		{
			$user = KunenaUserHelper::getMyself();
		}
		elseif (!($user instanceof KunenaUser))
		{
			$user = KunenaUserHelper::get($user);
		}

		$exception = $this->tryAuthorise($action, $user, false);

		if ($silent === false && $exception)
		{
			$this->setError($exception->getMessage());
		}

		KUNENA_PROFILER ? KunenaProfiler::instance()->stop('function '.__CLASS__.'::'.__FUNCTION__.'()') : null;

		if ($silent !== null)
		{
			return !$exception;
		}

		return $exception ? $exception->getMessage() : null;
	}

	/**
	 * @param array $fields
	 * @param mixed $user
	 */
	public function edit($fields = array(), $user = null)
	{
		$user = KunenaUserHelper::get($user);

		$this->bind($fields, array ('name', 'email', 'subject', 'message', 'modified_reason' ), true);

		// Update rest of the information
		$category = $this->getCategory();
		$this->hold = $category->review && !$category->authorise('moderate', $user, true) ? 1 : $this->hold;
		$this->modified_by = $user->userid;
		$this->modified_time = JFactory::getDate()->toUnix();
	}

	/**
	 * @param mixed $user
	 */
	public function makeAnonymous($user = null)
	{
		$user = KunenaUserHelper::get($user);

		if ($user->userid == $this->userid && $this->modified_by == $this->userid)
		{
			// I am the author and previous modification was made by me => delete modification information to hide my personality
			$this->modified_by = 0;
			$this->modified_time = 0;
			$this->modified_reason = '';
		}
		else if ($user->userid == $this->userid)
		{
			// I am the author, but somebody else has modified the message => leave modification information intact
			$this->modified_by = null;
			$this->modified_time = null;
			$this->modified_reason = null;
		}

		// Remove userid, email and ip address
		$this->userid = 0;
		$this->ip = '';
		$this->email = '';
	}

	/**
	 * @param int    $tmpid
	 * @param string $postvar
	 * @param null   $catid
	 *
	 * @return bool
	 */
	public function uploadAttachment($tmpid, $postvar, $catid = null)
	{
		$attachment = new KunenaAttachment;
		$attachment->userid = $this->userid;
		$success = $attachment->upload($postvar, $catid);
		$this->_attachments_add[$tmpid] = $attachment;

		return $success;
	}

	/**
	 * Add listed attachments to the message.
	 *
	 * If attachment is already pointing to the message, this function has no effect.
	 * Currently only orphan attachments can be added.
	 *
	 * @param array $ids
	 * @since  K4.0
	 */
	public function addAttachments(array $ids)
	{
		$this->_attachments_add += $this->getAttachments($ids, 'none');
	}

	/**
	 * Remove listed attachments from the message.
	 *
	 * @param array $ids
	 * @since  K4.0
	 */
	public function removeAttachments(array $ids)
	{
		$this->_attachments_del += $this->getAttachments($ids, 'none');
	}

	/**
	 * Remove listed attachments from the message.
	 *
	 * @param bool|int|array $ids
	 * @deprecated K4.0
	 */
	public function removeAttachment($ids)
	{
		if ($ids === false)
		{
			$ids = array_keys($this->getAttachments());
		}
		elseif (!is_array($ids))
		{
			$ids = array((int) $ids);
		}

		$this->removeAttachments($ids);
	}

	/**
	 * Get the number of attachments into a message
	 *
	 * @return array
	 */
	public function getNbAttachments()
	{
		$attachments = KunenaAttachmentHelper::getNumberAttachments($this->id);

		$attachs = new StdClass();
		$attachs->image = 0;
		$attachs->file = 0;
		$attachs->total = 0;

		foreach($attachments as $attach)
		{
			if ($attach->isImage())
			{
				$attachs->image = $attachs->image+1;
			}
			else
			{
				$attachs->file = $attachs->file+1;
			}

      $attachs->total = $attachs->total+1;
		}

		return $attachs;
	}

	/**
	 * @param  bool|array  $ids
	 * @param  string      $action
	 *
	 * @return KunenaAttachment[]
	 */
	public function getAttachments($ids=false, $action = 'read')
	{
		if ($ids === false)
		{
			$attachments = KunenaAttachmentHelper::getByMessage($this->id, $action);
		}
		else
		{
			$attachments = KunenaAttachmentHelper::getById($ids, $action);

			foreach ($attachments as $id=>$attachment)
			{
				if ($attachment->mesid && $attachment->mesid != $this->id)
				{
					unset($attachments[$id]);
				}
			}
		}

		return $attachments;
	}

	/**
	 * @return bool
	 */
	protected function updateAttachments()
	{
		// Save new attachments and update message text
		$message = $this->message;
		foreach ($this->_attachments_add as $tmpid=>$attachment)
		{
			if ($attachment->exists() && $attachment->mesid)
			{
				// Attachment exists and already belongs to a message => update.
				if (!$attachment->save())
				{
					$this->setError($attachment->getError());
					continue;
				}

				continue;
			}

			$attachment->mesid = $this->id;

			if ($attachment->IsImage())
			{
				$exception = $attachment->tryAuthorise('createimage', null, false);
			}
			else
			{
				$exception = $attachment->tryAuthorise('createfile', null, false);
			}

			if ($exception)
			{
				$this->setError($exception->getMessage());
				continue;
			}

			if (!$attachment->save())
			{
				$this->setError($attachment->getError());
				continue;
			}

			// Update attachments count and fix attachment name inside message
			$this->getTopic()->attachments++;
			$this->message = preg_replace('/\[attachment\:'.$tmpid.'\].*?\[\/attachment\]/u', "[attachment={$attachment->id}]{$attachment->filename}[/attachment]", $this->message);
		}

		// Delete removed attachments and update attachments count and message text
		foreach ($this->_attachments_del as $attachment)
		{
			if ($attachment->mesid && $attachment->mesid != $this->id)
			{
				// Attachment doesn't belong to this message => skip it.
				continue;
			}

			$exception = $attachment->tryAuthorise('delete', null, false);

			if ($exception)
			{
				$this->setError($exception->getMessage());
				continue;
			}

			if (!$attachment->delete())
			{
				$this->setError($attachment->getError());
			}
			else
			{
				$this->getTopic()->attachments--;
			}

			$this->message = preg_replace('/\[attachment\='.$attachment->id.'\].*?\[\/attachment\]/u', '', $this->message);
			$this->message = preg_replace('/\[attachment\]'.$attachment->filename.'\[\/attachment\]/u', '', $this->message);
		}

		// Remove missing temporary attachments from the message text
		$this->message = trim(preg_replace('/\[attachment\:\d+\].*?\[\/attachment\]/u', '', $this->message));

		// Return true if we changed the message contents
		return ($this->message != $message);
	}

	/**
	 * Method to load a KunenaForumMessage object by id.
	 *
	 * @param mixed $id	The message id to be loaded
	 *
	 * @return bool	True on success
	 */
	public function load($id = null)
	{
		$exists = parent::load($id);
		$this->_hold = $exists ? $this->hold : 1;
		$this->_thread = $this->thread;

		return $exists;
	}

	/**
	 * Method to save the KunenaForumMessage object to the database.
	 *
	 * @return	boolean True on success
	 */
	public function save()
	{
		$isNew = ! $this->_exists;

		$topic = $this->getTopic();
		$newTopic = !$topic->exists();

		if ($newTopic) {
			// Create topic, but do not cascade changes to category etc..
			if (!$topic->save(false))
			{
				$this->setError ( $topic->getError () );
				return false;
			}

			$this->_thread = $this->thread = $topic->id;
		}

		// Create message
		if (! parent::save ())
		{
			// If we created a new topic, remember to delete it too.
			if ($newTopic)
			{
				$topic->delete();
			}

			return false;
		}

		if ($isNew) {
			$this->_hold = 1;
		}

		// Update attachments and message text
		$update = $this->updateAttachments();

		// Did we change anything?
		if ($update)
		{
			if ($isNew && trim($this->message) == '')
			{
				// Oops, no attachments remain and the message becomes empty.
				// Let's delete the new message and fail on save.
				$this->delete();

				// If we created a new topic, remember to delete it too.
				if ($newTopic)
				{
					$topic->delete();
				}

				$this->setError(JText::_('COM_KUNENA_LIB_TABLE_MESSAGES_ERROR_NO_MESSAGE'));

				return false;
			}

			$table = $this->getTable ();
			$table->bind ( $this->getProperties () );
			$table->exists(true);

			if (! $table->store ())
			{
				$this->setError ( $table->getError () );
				return false;
			}
		}

		// Cascade changes to other tables
		$this->update($newTopic);

		return true;
	}

	/**
	 * Method to delete the KunenaForumMessage object from the database.
	 *
	 * @return bool	True on success
	 */
	public function delete()
	{
		if (!$this->exists())
		{
			return true;
		}

		if (!parent::delete())
		{
			return false;
		}

		$this->hold = 1;

		$attachments = $this->getAttachments();
		foreach ($attachments as $attachment)
		{
			$file = JUri::root() . $attachment->filename;
			KunenaFile::delete($file);

			if (!$attachment->delete())
			{
				$this->setError ( $attachment->getError() );
			}
		}

		$db = JFactory::getDBO ();
		// Delete thank yous
		$queries[] = "DELETE FROM #__kunena_thankyou WHERE postid={$db->quote($this->id)}";
		// Delete message
		$queries[] = "DELETE FROM #__kunena_messages_text WHERE mesid={$db->quote($this->id)}";

		// Cascade changes into other tables
		$this->update();

		foreach ($queries as $query)
		{
			$db->setQuery($query);

			try
			{
				$db->execute();
			}
			catch (JDatabaseExceptionExecuting $e)
 			{
 				KunenaError::displayDatabaseError($e);
 			}
		}

		KunenaForumMessageThankyouHelper::recount();

		return true;
	}

	/**
	 * @return bool
	 */
	public function check()
	{
		$author = KunenaUserHelper::get($this->userid);

		// Check username
		if (! $this->userid)
		{
			$this->name = trim($this->name);
			// Unregistered or anonymous users: Do not allow existing username
			$nicktaken = JUserHelper::getUserId ( $this->name );
			if (empty ( $this->name ) || $nicktaken)
			{
				$this->name = JText::_ ( 'COM_KUNENA_USERNAME_ANONYMOUS' );
			}
		}
		else
		{
			$this->name = $author->getName();
		}

		// Check email address
		$this->email = trim($this->email);

		if ($this->email)
		{
			// Email address must be valid
			if (! JMailHelper::isEmailAddress ( $this->email ))
			{
				$this->setError ( JText::sprintf ( 'COM_KUNENA_LIB_MESSAGE_ERROR_EMAIL_INVALID' ) );

				return false;
			}
		}
		else if (! KunenaUserHelper::getMyself()->exists() && KunenaFactory::getConfig()->askemail)
		{
			$this->setError ( JText::_ ( 'COM_KUNENA_LIB_MESSAGE_ERROR_EMAIL_EMPTY' ) );

			return false;
		}

		// Do not allow no posting date or dates from the future
		$now = JFactory::getDate()->toUnix();
		if (!$this->time || $this->time > $now)
		{
			$this->time = $now;
		}

		// Do not allow indentical posting times inside topic (simplifies logic)
		$topic = $this->getTopic();

		if (!$this->exists() && $topic->exists() && $this->time <= $topic->last_post_time)
		{
			$this->time = $topic->last_post_time + 1;
		}

		if ($this->modified_time > $now)
		{
			$this->modified_time = $now;
		}

		if ($this->modified_time && $this->modified_time < $this->time)
		{
			$this->modified_time = $this->time;
		}

		if ($this->hold < 0 || $this->hold > 3)
		{
			$this->setError ( JText::_ ( 'COM_KUNENA_LIB_MESSAGE_ERROR_HOLD_INVALID' ) );

			return false;
		}

		if ($this->modified_by !== null)
		{
			if (!$this->modified_by)
			{
				$this->modified_time = 0;
				$this->modified_reason = '';
			}
			elseif (!$this->modified_time)
			{
				$this->modified_time = JFactory::getDate()->toUnix();
			}
		}

		// Flood protection
		$config = KunenaFactory::getConfig();

		if ($config->floodprotection && !$this->getCategory()->authorise('moderate') && !$this->exists())
		{
			$this->_db->setQuery ( "SELECT MAX(time) FROM #__kunena_messages WHERE ip={$this->_db->quote($this->ip)}" );
			$lastPostTime = $this->_db->loadResult ();

			if ($this->_db->getErrorNum())
			{
				$this->setError ( $this->_db->getErrorMsg() );
				return false;
			}

			if ($lastPostTime + $config->floodprotection > JFactory::getDate()->toUnix())
			{
				$this->setError ( JText::sprintf ( 'COM_KUNENA_LIB_MESSAGE_ERROR_FLOOD', (int)$config->floodprotection ) );
				return false;
			}
		}

		if (!$this->exists() && !$this->getCategory()->authorise('moderate'))
		{
			// Ignore identical messages (posted within 5 minutes)
			$duplicatetimewindow = JFactory::getDate ()->toUnix() - 5 * 60;
			$this->_db->setQuery ( "SELECT m.id FROM #__kunena_messages AS m INNER JOIN #__kunena_messages_text AS t ON m.id=t.mesid
				WHERE m.userid={$this->_db->quote($this->userid)}
				AND m.ip={$this->_db->quote($this->ip)}
				AND t.message={$this->_db->quote($this->message)}
				AND m.time>={$this->_db->quote($duplicatetimewindow)}" );
			$id = $this->_db->loadResult ();

			if ($this->_db->getErrorNum())
			{
				$this->setError ( $this->_db->getErrorMsg() );
				return false;
			}

			if ($id)
			{
				$this->setError ( JText::_ ( 'COM_KUNENA_POST_DUPLICATE_IGNORED' ) );
				return false;
			}
		}

		return true;
	}

	// Internal functions

	/**
	 * @param bool $newTopic
	 */
	protected function update($newTopic = false)
	{
		// If post was published and then moved, we need to update old topic
		if (!$this->_hold && $this->_thread && $this->_thread != $this->thread)
		{
			$topic = KunenaForumTopicHelper::get($this->_thread);

			if (! $topic->update($this, -1))
			{
				$this->setError ( $topic->getError () );
			}
		}

		$postDelta = $this->delta(true);
		$topic = $this->getTopic();

		// New topic
		if ($newTopic) {
			$topic->hold = 0;
		}
		// Update topic
		if (!$this->hold && $topic->hold && $topic->exists()) {
			// We published message -> publish and recount topic
			$topic->hold = 0;
			$topic->recount();
		} elseif (! $topic->update($this, $postDelta)) {
			$this->setError ( $topic->getError () );
		}

		// Activity integration
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');
		$activity = KunenaFactory::getActivityIntegration();

		if ($postDelta < 0)
		{
			$dispatcher->trigger('onDeleteKunenaPost', array(array($this->id)));
			$activity->onAfterDelete($this);
		}
		elseif ($postDelta > 0)
		{
			$topic->markRead();

			if ($this->parent == 0) {
				$activity->onAfterPost($this);
			}
			else {
				$activity->onAfterReply($this);
			}
		}
	}

	/**
	 * @param KunenaUser $user
	 *
	 * @return KunenaExceptionAuthorise|null
	 */
	protected function authoriseRead(KunenaUser $user)
	{
		if ($this->hold && !$user->exists())
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_NO_ACCESS'), 401);
		}

		// Check that user has the right to see the post (user can see his own unapproved posts)
		if ($this->hold > 1 || ($this->hold == 1 && $this->userid != $user->userid))
		{
			$access = KunenaAccess::getInstance();
			$hold = $access->getAllowedHold($user->userid, $this->catid, false);

			if (!in_array($this->hold, $hold))
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_NO_ACCESS'), 403);
			}
		}

		return null;
	}

	/**
	 * @param KunenaUser $user
	 *
	 * @return KunenaExceptionAuthorise|null
	 */
	protected function authoriseNotHold(KunenaUser $user)
	{
		if ($this->hold)
		{
			// Nobody can reply to unapproved or deleted post
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_NO_ACCESS'), 403);
		}

		return null;
	}

	/**
	 * @param KunenaUser $user
	 *
	 * @return KunenaExceptionAuthorise|null
	 */
	protected function authoriseOwn(KunenaUser $user)
	{
		// Guests cannot own posts.
		if (!$user->exists())
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_EDIT_NOT_ALLOWED'), 401);
		}

		// Check that topic owned by the user or user is a moderator
		// TODO: check #__kunena_user_topics
		if ($this->userid != $user->userid && !$user->isModerator($this->getCategory()))
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_EDIT_NOT_ALLOWED'), 403);
		}

		return null;
	}

	/**
	 * @param KunenaUser $user
	 *
	 * @return KunenaExceptionAuthorise|null
	 */
	protected function authoriseThankyou(KunenaUser $user)
	{
		// Check that message is not your own
		if(!KunenaFactory::getConfig()->showthankyou)
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_THANKYOU_DISABLED'), 403);
		}

		if (!$user->userid)
		{
			// TODO: better error message
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_THANKYOU_DISABLED'), 401);
		}

		if (!$this->userid || $this->userid == $user->userid)
		{
			// TODO: better error message
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_THANKYOU_DISABLED'), 403);
		}

		return null;
	}

	/**
	 * This function check the edit time from the author of the post and return if the user is allowed to edit his post.
	 *
	 * @param KunenaUser $user
	 *
	 * @return KunenaExceptionAuthorise|null
	 */
	protected function authoriseEditTime(KunenaUser $user)
	{
		// Do not perform rest of the checks to moderators and admins
		if ($user->isModerator($this->getCategory()))
		{
			return null;
		}

		// User is only allowed to edit post within time specified in the configuration
		$config = KunenaFactory::getConfig();

		if (intval($config->useredit) == 0)
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_EDIT_NOT_ALLOWED'), 403);
		}

		if (intval($config->useredit) == 2 && $this->getTopic()->getReplies())
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_EDIT_NOT_ALLOWED'), 403);
		}

		if ($this->getTopic()->getReplies() && $this->getTopic()->last_post_id > $this->id)
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_EDIT_NOT_ALLOWED'), 403);
		}

		if (intval($config->useredittime) != 0)
		{
			//Check whether edit is in time
			$modtime = $this->modified_time ? $this->modified_time : $this->time;

			if ($modtime + intval($config->useredittime) < JFactory::getDate()->toUnix())
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_EDIT_NOT_ALLOWED'), 403);
			}
		}

		return null;
	}

	/**
	 * @param KunenaUser $user
	 *
	 * @return KunenaExceptionAuthorise|null
	 */
	protected function authoriseDelete(KunenaUser $user)
	{
		$config = KunenaFactory::getConfig();

		if (!$user->isModerator($this->getCategory()) && $config->userdeletetmessage != '2')
		{
			if ($config->userdeletetmessage == '0')
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ERROR_DELETE_REPLY_AFTER'), 403);
			}

			if ($config->userdeletetmessage == '1' && ($this->getTopic()->first_post_id != $this->id || $this->getTopic()->getReplies()))
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ERROR_DELETE_REPLY_AFTER'), 403);
			}

			if ($config->userdeletetmessage == '3' && $this->id == $this->getTopic()->first_post_id)
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ERROR_DELETE_REPLY_AFTER'), 403);
			}
		}
	}

	/**
	 * @param   KunenaUser $user
	 *
	 * @return null|string
	 */
	protected function authorisePermdelete(KunenaUser $user)
	{
		$config = KunenaFactory::getConfig();

		if ($user->isAdmin() || $user->isModerator())
		{
			return null;
		}

		if ($user->isModerator($this->getTopic()->getCategory()) && !$config->moderator_permdelete || !$user->isModerator($this->getTopic()->getCategory()))
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ERROR_DELETE_REPLY_AFTER'), 403);
		}

		return null;
	}

	/**
	 * Check if user has the right to upload image attachment
	 *
	 * @param KunenaUser $user
	 * @return KunenaExceptionAuthorise|NULL
	 */
	protected function authoriseAttachmentsImage(KunenaUser $user)
	{
		if (empty(KunenaFactory::getConfig()->image_upload))
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ATTACHMENTS_NOT_ALLOWED'), 403);
		}

		if (KunenaFactory::getConfig()->image_upload=='admin'  )
		{
			if (!$user->isAdmin())
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ATTACHMENTS_IMAGE_ONLY_FOR_ADMINISTRATORS'), 403);
			}
		}

		if (KunenaFactory::getConfig()->image_upload=='registered')
		{
			if (!$user->userid )
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ATTACHMENTS_IMAGE_ONLY_FOR_REGISTERED_USERS'), 403);
			}
		}

		if (KunenaFactory::getConfig()->image_upload=='moderator')
		{
			$category = $this->getCategory();
			if (!$user->isModerator($category))
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ATTACHMENTS_IMAGE_ONLY_FOR_MODERATORS'), 403);
			}
		}

		return null;
	}

	/**
	 * Check if user has the right to upload file attachment
	 *
	 * @param KunenaUser $user
	 * @return KunenaExceptionAuthorise|NULL
	 */
	protected function authoriseAttachmentsFile(KunenaUser $user)
	{
		if (empty(KunenaFactory::getConfig()->file_upload) )
		{
			return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ATTACHMENTS_NOT_ALLOWED'), 403);
		}

		if (KunenaFactory::getConfig()->file_upload=='admin')
		{
			if (!$user->isAdmin())
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ATTACHMENTS_FILE_ONLY_FOR_ADMINISTRATORS'), 403);
			}
		}

		if(KunenaFactory::getConfig()->file_upload=='registered' )
		{
			if (!$user->userid )
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ATTACHMENTS_FILE_ONLY_FOR_REGISTERED_USERS'), 403);
			}
		}

		if (KunenaFactory::getConfig()->file_upload=='moderator' )
		{
			$category = $this->getCategory();
			if (!$user->isModerator($category))
			{
				return new KunenaExceptionAuthorise(JText::_('COM_KUNENA_POST_ATTACHMENTS_FILE_ONLY_FOR_MODERATORS'), 403);
			}
		}

		return null;
	}

	/**
	 * @return int
	 */
	protected function delta()
	{
		if (!$this->hold && ($this->_hold || $this->thread != $this->_thread))
		{
			// Publish message or move it into new topic
			return 1;
		}
		elseif (!$this->_hold && $this->hold)
		{
			// Unpublish message
			return -1;
		}

		return 0;
	}

	/**
	 * @param JMail $mail
	 * @param int $subscription
	 * @param string $subject
	 * @param string $url
	 * @param bool $once
	 *
	 * @return string
	 */
	protected function attachEmailBody($mail, $subscription, $subject, $url, $once)
	{
		$layout = KunenaLayout::factory('Email/Subscription')->debug(false)
			->set('mail', $mail)
			->set('message', $this)
			->set('messageUrl', $url)
			->set('once', $once);

		try
		{
			$msg = trim($layout->render($subscription ? 'default' : 'moderator'));
		}
		catch (Exception $e)
		{
		}

		$mail->setBody($msg);
	}

	/**
	 * Get the substring
	 *
	 * @param $string
	 * @param $start
	 * @param $length
	 *
	 * @return string
	 * @since K5.0.2
	 */
	public function getsubstr($string, $start, $length)
	{
		$mbString = extension_loaded('mbstring');

		if ($mbString)
		{
			$title = mb_substr($string, $start, $length);
		}
		else
		{
			$title2 = substr($string, $start, $length);
			$title  = preg_replace('/[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]'.
				'|[\x00-\x7F][\x80-\xBF]+'.
				'|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*'.
				'|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})'.
				'|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/S',
				'', $title2);
		}

		return $title;
	}
}

Anon7 - 2022
AnonSec Team