Spade

Mini Shell

Directory:~$ /home/lmsyaran/public_html/joomla4/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ /home/lmsyaran/public_html/joomla4/plugins.tar

actionlog/joomla/joomla.php000064400000071772147357022230012021
0ustar00<?php
/**
 * @package     Joomla.Plugins
 * @subpackage  System.actionlogs
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\User\User;
use Joomla\CMS\Version;
use Joomla\Utilities\ArrayHelper;

JLoader::register('ActionLogPlugin', JPATH_ADMINISTRATOR .
'/components/com_actionlogs/libraries/actionlogplugin.php');
JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR .
'/components/com_actionlogs/helpers/actionlogs.php');

/**
 * Joomla! Users Actions Logging Plugin.
 *
 * @since  3.9.0
 */
class PlgActionlogJoomla extends ActionLogPlugin
{
	/**
	 * Array of loggable extensions.
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $loggableExtensions = array();

	/**
	 * Context aliases
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $contextAliases = array('com_content.form' =>
'com_content.article');

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of
configuration settings.
	 *
	 * @since   3.9.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		$params =
ComponentHelper::getComponent('com_actionlogs')->getParams();

		$this->loggableExtensions =
$params->get('loggable_extensions', array());
	}

	/**
	 * After save content logging method
	 * This method adds a record to #__action_logs contains (message, date,
context, user)
	 * Method is called right after the content is saved
	 *
	 * @param   string   $context  The context of the content passed to the
plugin
	 * @param   object   $article  A JTableContent object
	 * @param   boolean  $isNew    If the content is just about to be created
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onContentAfterSave($context, $article, $isNew)
	{
		if (isset($this->contextAliases[$context]))
		{
			$context = $this->contextAliases[$context];
		}

		$option = $this->app->input->getCmd('option');

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		list(, $contentType) = explode('.', $params->type_alias);

		if ($isNew)
		{
			$messageLanguageKey = $params->text_prefix . '_' .
$params->type_title . '_ADDED';
			$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED';
		}
		else
		{
			$messageLanguageKey = $params->text_prefix . '_' .
$params->type_title . '_UPDATED';
			$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED';
		}

		// If the content type doesn't has it own language key, use default
language key
		if (!$this->app->getLanguage()->hasKey($messageLanguageKey))
		{
			$messageLanguageKey = $defaultLanguageKey;
		}

		$id = empty($params->id_holder) ? 0 :
$article->get($params->id_holder);

		$message = array(
			'action'   => $isNew ? 'add' :
'update',
			'type'     => $params->text_prefix . '_TYPE_'
. $params->type_title,
			'id'       => $id,
			'title'    => $article->get($params->title_holder),
			'itemlink' => ActionlogsHelper::getContentTypeLink($option,
$contentType, $id, $params->id_holder, $article),
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * After delete content logging method
	 * This method adds a record to #__action_logs contains (message, date,
context, user)
	 * Method is called right after the content is deleted
	 *
	 * @param   string  $context  The context of the content passed to the
plugin
	 * @param   object  $article  A JTableContent object
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onContentAfterDelete($context, $article)
	{
		$option = $this->app->input->get('option');

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		// If the content type has it own language key, use it, otherwise, use
default language key
		if
($this->app->getLanguage()->hasKey(strtoupper($params->text_prefix
. '_' . $params->type_title . '_DELETED')))
		{
			$messageLanguageKey = $params->text_prefix . '_' .
$params->type_title . '_DELETED';
		}
		else
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED';
		}

		$id = empty($params->id_holder) ? 0 :
$article->get($params->id_holder);

		$message = array(
			'action' => 'delete',
			'type'   => $params->text_prefix . '_TYPE_' .
$params->type_title,
			'id'     => $id,
			'title'  => $article->get($params->title_holder)
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On content change status logging method
	 * This method adds a record to #__action_logs contains (message, date,
context, user)
	 * Method is called when the status of the article is changed
	 *
	 * @param   string   $context  The context of the content passed to the
plugin
	 * @param   array    $pks      An array of primary key ids of the content
that has changed state.
	 * @param   integer  $value    The value of the state that the content has
been changed to.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onContentChangeState($context, $pks, $value)
	{
		$option = $this->app->input->getCmd('option');

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		list(, $contentType) = explode('.', $params->type_alias);

		switch ($value)
		{
			case 0:
				$messageLanguageKey = $params->text_prefix . '_' .
$params->type_title . '_UNPUBLISHED';
				$defaultLanguageKey =
'PLG_SYSTEM_ACTIONLOGS_CONTENT_UNPUBLISHED';
				$action             = 'unpublish';
				break;
			case 1:
				$messageLanguageKey = $params->text_prefix . '_' .
$params->type_title . '_PUBLISHED';
				$defaultLanguageKey =
'PLG_SYSTEM_ACTIONLOGS_CONTENT_PUBLISHED';
				$action             = 'publish';
				break;
			case 2:
				$messageLanguageKey = $params->text_prefix . '_' .
$params->type_title . '_ARCHIVED';
				$defaultLanguageKey =
'PLG_SYSTEM_ACTIONLOGS_CONTENT_ARCHIVED';
				$action             = 'archive';
				break;
			case -2:
				$messageLanguageKey = $params->text_prefix . '_' .
$params->type_title . '_TRASHED';
				$defaultLanguageKey =
'PLG_SYSTEM_ACTIONLOGS_CONTENT_TRASHED';
				$action             = 'trash';
				break;
			default:
				$messageLanguageKey = '';
				$defaultLanguageKey = '';
				$action             = '';
				break;
		}

		// If the content type doesn't has it own language key, use default
language key
		if (!$this->app->getLanguage()->hasKey($messageLanguageKey))
		{
			$messageLanguageKey = $defaultLanguageKey;
		}

		$db    = $this->db;
		$query = $db->getQuery(true)
			->select($db->quoteName(array($params->title_holder,
$params->id_holder)))
			->from($db->quoteName($params->table_name))
			->where($db->quoteName($params->id_holder) . ' IN ('
. implode(',', ArrayHelper::toInteger($pks)) . ')');
		$db->setQuery($query);

		try
		{
			$items = $db->loadObjectList($params->id_holder);
		}
		catch (RuntimeException $e)
		{
			$items = array();
		}

		$messages = array();

		foreach ($pks as $pk)
		{
			$message = array(
				'action'      => $action,
				'type'        => $params->text_prefix .
'_TYPE_' . $params->type_title,
				'id'          => $pk,
				'title'       =>
$items[$pk]->{$params->title_holder},
				'itemlink'    =>
ActionlogsHelper::getContentTypeLink($option, $contentType, $pk,
$params->id_holder, null)
			);

			$messages[] = $message;
		}

		$this->addLog($messages, $messageLanguageKey, $context);
	}

	/**
	 * On Saving application configuration logging method
	 * Method is called when the application config is being saved
	 *
	 * @param   JRegistry  $config  JRegistry object with the new config
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onApplicationAfterSave($config)
	{
		$option = $this->app->input->getCmd('option');

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$messageLanguageKey =
'PLG_ACTIONLOG_JOOMLA_APPLICATION_CONFIG_UPDATED';
		$action             = 'update';

		$message = array(
			'action'         => $action,
			'type'           =>
'PLG_ACTIONLOG_JOOMLA_TYPE_APPLICATION_CONFIG',
			'extension_name' => 'com_config.application',
			'itemlink'       => 'index.php?option=com_config'
		);

		$this->addLog(array($message), $messageLanguageKey,
'com_config.application');
	}

	/**
	 * On installing extensions logging method
	 * This method adds a record to #__action_logs contains (message, date,
context, user)
	 * Method is called when an extension is installed
	 *
	 * @param   JInstaller  $installer  Installer object
	 * @param   integer     $eid        Extension Identifier
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterInstall($installer, $eid)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$manifest      = $installer->get('manifest');

		if ($manifest === null)
		{
			return;
		}

		$extensionType = $manifest->attributes()->type;

		// If the extension type has it own language key, use it, otherwise, use
default language key
		if
($this->app->getLanguage()->hasKey(strtoupper('PLG_ACTIONLOG_JOOMLA_'
. $extensionType . '_INSTALLED')))
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_' . $extensionType
. '_INSTALLED';
		}
		else
		{
			$messageLanguageKey =
'PLG_ACTIONLOG_JOOMLA_EXTENSION_INSTALLED';
		}

		$message = array(
			'action'         => 'install',
			'type'           => 'PLG_ACTIONLOG_JOOMLA_TYPE_'
. $extensionType,
			'id'             => $eid,
			'name'           => (string) $manifest->name,
			'extension_name' => (string) $manifest->name
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On uninstalling extensions logging method
	 * This method adds a record to #__action_logs contains (message, date,
context, user)
	 * Method is called when an extension is uninstalled
	 *
	 * @param   JInstaller  $installer  Installer instance
	 * @param   integer     $eid        Extension id
	 * @param   integer     $result     Installation result
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterUninstall($installer, $eid, $result)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		// If the process failed, we don't have manifest data, stop process
to avoid fatal error
		if ($result === false)
		{
			return;
		}

		$manifest      = $installer->get('manifest');

		if ($manifest === null)
		{
			return;
		}

		$extensionType = $manifest->attributes()->type;

		// If the extension type has it own language key, use it, otherwise, use
default language key
		if
($this->app->getLanguage()->hasKey(strtoupper('PLG_ACTIONLOG_JOOMLA_'
. $extensionType . '_UNINSTALLED')))
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_' . $extensionType
. '_UNINSTALLED';
		}
		else
		{
			$messageLanguageKey =
'PLG_ACTIONLOG_JOOMLA_EXTENSION_UNINSTALLED';
		}

		$message = array(
			'action'         => 'install',
			'type'           => 'PLG_ACTIONLOG_JOOMLA_TYPE_'
. $extensionType,
			'id'             => $eid,
			'name'           => (string) $manifest->name,
			'extension_name' => (string) $manifest->name
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On updating extensions logging method
	 * This method adds a record to #__action_logs contains (message, date,
context, user)
	 * Method is called when an extension is updated
	 *
	 * @param   JInstaller  $installer  Installer instance
	 * @param   integer     $eid        Extension id
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterUpdate($installer, $eid)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$manifest      = $installer->get('manifest');

		if ($manifest === null)
		{
			return;
		}

		$extensionType = $manifest->attributes()->type;

		// If the extension type has it own language key, use it, otherwise, use
default language key
		if
($this->app->getLanguage()->hasKey('PLG_ACTIONLOG_JOOMLA_'
. $extensionType . '_UPDATED'))
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_' . $extensionType
. '_UPDATED';
		}
		else
		{
			$messageLanguageKey =
'PLG_ACTIONLOG_JOOMLA_EXTENSION_UPDATED';
		}

		$message = array(
			'action'         => 'update',
			'type'           => 'PLG_ACTIONLOG_JOOMLA_TYPE_'
. $extensionType,
			'id'             => $eid,
			'name'           => (string) $manifest->name,
			'extension_name' => (string) $manifest->name
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On Saving extensions logging method
	 * Method is called when an extension is being saved
	 *
	 * @param   string   $context  The extension
	 * @param   JTable   $table    DataBase Table object
	 * @param   boolean  $isNew    If the extension is new or not
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterSave($context, $table, $isNew)
	{
		$option = $this->app->input->getCmd('option');

		if ($table->get('module') != null)
		{
			$option = 'com_modules';
		}

		if (!$this->checkLoggable($option))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		list(, $contentType) = explode('.', $params->type_alias);

		if ($isNew)
		{
			$messageLanguageKey = $params->text_prefix . '_' .
$params->type_title . '_ADDED';
			$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED';
		}
		else
		{
			$messageLanguageKey = $params->text_prefix . '_' .
$params->type_title . '_UPDATED';
			$defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED';
		}

		// If the extension type doesn't have it own language key, use
default language key
		if (!$this->app->getLanguage()->hasKey($messageLanguageKey))
		{
			$messageLanguageKey = $defaultLanguageKey;
		}

		$message = array(
			'action'         => $isNew ? 'add' :
'update',
			'type'           => 'PLG_ACTIONLOG_JOOMLA_TYPE_'
. $params->type_title,
			'id'             => $table->get($params->id_holder),
			'title'          =>
$table->get($params->title_holder),
			'extension_name' =>
$table->get($params->title_holder),
			'itemlink'       =>
ActionlogsHelper::getContentTypeLink($option, $contentType,
$table->get($params->id_holder), $params->id_holder, null)
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On Deleting extensions logging method
	 * Method is called when an extension is being deleted
	 *
	 * @param   string  $context  The extension
	 * @param   JTable  $table    DataBase Table object
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onExtensionAfterDelete($context, $table)
	{
		if
(!$this->checkLoggable($this->app->input->get('option')))
		{
			return;
		}

		$params = ActionlogsHelper::getLogContentTypeParams($context);

		// Not found a valid content type, don't process further
		if ($params === null)
		{
			return;
		}

		$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED';

		$message = array(
			'action' => 'delete',
			'type'   => 'PLG_ACTIONLOG_JOOMLA_TYPE_' .
$params->type_title,
			'title'  => $table->get($params->title_holder)
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On saving user data logging method
	 *
	 * Method is called after user data is stored in the database.
	 * This method logs who created/edited any user's data
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isnew    True if a new user is stored.
	 * @param   boolean  $success  True if user was successfully stored in the
database.
	 * @param   string   $msg      Message.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		$context = $this->app->input->get('option');
		$task    = $this->app->input->get->getCmd('task');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$jUser = Factory::getUser();

		if (!$jUser->id)
		{
			$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_REGISTERED';
			$action             = 'register';

			// Reset request
			if ($task === 'reset.request')
			{
				$messageLanguageKey =
'PLG_ACTIONLOG_JOOMLA_USER_RESET_REQUEST';
				$action             = 'resetrequest';
			}

			// Reset complete
			if ($task === 'reset.complete')
			{
				$messageLanguageKey =
'PLG_ACTIONLOG_JOOMLA_USER_RESET_COMPLETE';
				$action             = 'resetcomplete';
			}

			// Registration Activation
			if ($task === 'registration.activate')
			{
				$messageLanguageKey =
'PLG_ACTIONLOG_JOOMLA_USER_REGISTRATION_ACTIVATE';
				$action             = 'activaterequest';
			}
		}
		elseif ($isnew)
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED';
			$action             = 'add';
		}
		else
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED';
			$action             = 'update';
		}

		$userId   = $jUser->id ?: $user['id'];
		$username = $jUser->username ?: $user['username'];

		$message = array(
			'action'      => $action,
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user['id'],
			'title'       => $user['name'],
			'itemlink'    =>
'index.php?option=com_users&task=user.edit&id=' .
$user['id'],
			'userid'      => $userId,
			'username'    => $username,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$userId,
		);

		$this->addLog(array($message), $messageLanguageKey, $context,
$userId);
	}

	/**
	 * On deleting user data logging method
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the
database
	 * @param   string   $msg      Message
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED';

		$message = array(
			'action'      => 'delete',
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user['id'],
			'title'       => $user['name']
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On after save user group data logging method
	 *
	 * Method is called after user group is stored into the database
	 *
	 * @param   string   $context  The context
	 * @param   JTable   $table    DataBase Table object
	 * @param   boolean  $isNew    Is new or not
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSaveGroup($context, $table, $isNew)
	{
		// Override context (com_users.group) with the component context
(com_users) to pass the checkLoggable
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		if ($isNew)
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED';
			$action             = 'add';
		}
		else
		{
			$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED';
			$action             = 'update';
		}

		$message = array(
			'action'      => $action,
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER_GROUP',
			'id'          => $table->id,
			'title'       => $table->title,
			'itemlink'    =>
'index.php?option=com_users&task=group.edit&id=' .
$table->id
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * On deleting user group data logging method
	 *
	 * Method is called after user group is deleted from the database
	 *
	 * @param   array    $group    Holds the group data
	 * @param   boolean  $success  True if user was successfully stored in the
database
	 * @param   string   $msg      Message
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterDeleteGroup($group, $success, $msg)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$messageLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED';

		$message = array(
			'action'      => 'delete',
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER_GROUP',
			'id'          => $group['id'],
			'title'       => $group['title']
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * Method to log user login success action
	 *
	 * @param   array  $options  Array holding options (user, responseType)
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterLogin($options)
	{
		$context = 'com_users';

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$loggedInUser       = $options['user'];
		$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_LOGGED_IN';

		$message = array(
			'action'      => 'login',
			'userid'      => $loggedInUser->id,
			'username'    => $loggedInUser->username,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$loggedInUser->id,
			'app'         =>
'PLG_ACTIONLOG_JOOMLA_APPLICATION_' .
$this->app->getName(),
		);

		$this->addLog(array($message), $messageLanguageKey, $context,
$loggedInUser->id);
	}

	/**
	 * Method to log user login failed action
	 *
	 * @param   array  $response  Array of response data.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserLoginFailure($response)
	{
		$context = 'com_users';

		if (!$this->checkLoggable($context))
		{
			return;
		}

		// Get the user id for the given username
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('id',
'username')))
			->from($this->db->quoteName('#__users'))
			->where($this->db->quoteName('username') . ' =
' . $this->db->quote($response['username']));
		$this->db->setQuery($query);

		try
		{
			$loggedInUser = $this->db->loadObject();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return;
		}

		// Not a valid user, return
		if (!isset($loggedInUser->id))
		{
			return;
		}

		$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_LOGIN_FAILED';

		$message = array(
			'action'      => 'login',
			'id'          => $loggedInUser->id,
			'userid'      => $loggedInUser->id,
			'username'    => $loggedInUser->username,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$loggedInUser->id,
			'app'         =>
'PLG_ACTIONLOG_JOOMLA_APPLICATION_' .
$this->app->getName(),
		);

		$this->addLog(array($message), $messageLanguageKey, $context,
$loggedInUser->id);
	}

	/**
	 * Method to log user's logout action
	 *
	 * @param   array  $user     Holds the user data
	 * @param   array  $options  Array holding options (remember,
autoregister, group)
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserLogout($user, $options = array())
	{
		$context = 'com_users';

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$loggedOutUser = User::getInstance($user['id']);

		if ($loggedOutUser->block)
		{
			return;
		}

		$messageLanguageKey = 'PLG_ACTIONLOG_JOOMLA_USER_LOGGED_OUT';

		$message = array(
			'action'      => 'logout',
			'id'          => $loggedOutUser->id,
			'userid'      => $loggedOutUser->id,
			'username'    => $loggedOutUser->username,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$loggedOutUser->id,
			'app'         =>
'PLG_ACTIONLOG_JOOMLA_APPLICATION_' .
$this->app->getName(),
		);

		$this->addLog(array($message), $messageLanguageKey, $context);
	}

	/**
	 * Function to check if a component is loggable or not
	 *
	 * @param   string  $extension  The extension that triggered the event
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	protected function checkLoggable($extension)
	{
		return in_array($extension, $this->loggableExtensions);
	}

	/**
	 * On after Remind username request
	 *
	 * Method is called after user request to remind their username.
	 *
	 * @param   array  $user  Holds the user data.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterRemind($user)
	{
		$context = $this->app->input->get('option');

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$message = array(
			'action'      => 'remind',
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->name,
			'itemlink'    =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
			'userid'      => $user->id,
			'username'    => $user->name,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
		);

		$this->addLog(array($message),
'PLG_ACTIONLOG_JOOMLA_USER_REMIND', $context, $user->id);
	}

	/**
	 * On after Check-in request
	 *
	 * Method is called after user request to check-in items.
	 *
	 * @param   array  $table  Holds the table name.
	 *
	 * @return  void
	 *
	 * @since   3.9.3
	 */
	public function onAfterCheckin($table)
	{
		$context = 'com_checkin';
		$user    = Factory::getUser();

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$message = array(
			'action'      => 'checkin',
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
			'table'       => $table,
		);

		$this->addLog(array($message),
'PLG_ACTIONLOG_JOOMLA_USER_CHECKIN', $context, $user->id);
	}

	/**
	 * On after log action purge
	 *
	 * Method is called after user request to clean action log items.
	 *
	 * @param   array  $group  Holds the group name.
	 *
	 * @return  void
	 *
	 * @since   3.9.4
	 */
	public function onAfterLogPurge($group = '')
	{
		$context = $this->app->input->get('option');
		$user    = Factory::getUser();
		$message = array(
			'action'      => 'actionlogs',
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
		);
		$this->addLog(array($message),
'PLG_ACTIONLOG_JOOMLA_USER_LOG', $context, $user->id);
	}

	/**
	 * On after log export
	 *
	 * Method is called after user request to export action log items.
	 *
	 * @param   array  $group  Holds the group name.
	 *
	 * @return  void
	 *
	 * @since   3.9.4
	 */
	public function onAfterLogExport($group = '')
	{
		$context = $this->app->input->get('option');
		$user    = Factory::getUser();
		$message = array(
			'action'      => 'actionlogs',
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
		);
		$this->addLog(array($message),
'PLG_ACTIONLOG_JOOMLA_USER_LOGEXPORT', $context, $user->id);
	}

	/**
	 * On after Cache purge
	 *
	 * Method is called after user request to clean cached items.
	 *
	 * @param   string  $group  Holds the group name.
	 *
	 * @return  void
	 *
	 * @since   3.9.4
	 */
	public function onAfterPurge($group = 'all')
	{
		$context = $this->app->input->get('option');
		$user    = JFactory::getUser();

		if (!$this->checkLoggable($context))
		{
			return;
		}

		$message = array(
			'action'      => 'cache',
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
			'group'       => $group,
		);
		$this->addLog(array($message),
'PLG_ACTIONLOG_JOOMLA_USER_CACHE', $context, $user->id);
	}

	/**
	 * On after CMS Update
	 *
	 * Method is called after user update the CMS.
	 *
	 * @param   string  $oldVersion  The Joomla version before the update
	 *
	 * @return  void
	 *
	 * @since   3.9.21
	 */
	public function onJoomlaAfterUpdate($oldVersion = null)
	{
		$context = $this->app->input->get('option');
		$user    = JFactory::getUser();

		if (empty($oldVersion))
		{
			$oldVersion = JText::_('JLIB_UNKNOWN');
		}

		$message = array(
			'action'      => 'joomlaupdate',
			'type'        =>
'PLG_ACTIONLOG_JOOMLA_TYPE_USER',
			'id'          => $user->id,
			'title'       => $user->username,
			'itemlink'    =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
			'userid'      => $user->id,
			'username'    => $user->username,
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$user->id,
			'version'     => JVERSION,
			'oldversion'  => $oldVersion,
		);
		$this->addLog(array($message),
'PLG_ACTIONLOG_JOOMLA_USER_UPDATE', $context, $user->id);
	}
}
actionlog/joomla/joomla.xml000064400000001420147357022230012011
0ustar00<?xml version="1.0" encoding="UTF-8"?>
<extension version="3.9" type="plugin"
group="actionlog" method="upgrade">
	<name>PLG_ACTIONLOG_JOOMLA</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_ACTIONLOG_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_actionlog_joomla.ini</language>
		<language
tag="en-GB">en-GB.plg_actionlog_joomla.sys.ini</language>
	</languages>
</extension>
authentication/cookie/cookie.php000064400000026743147357022230013037
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Authentication.cookie
 *
 * @copyright   (C) 2013 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla Authentication plugin
 *
 * @since  3.2
 * @note   Code based on
http://jaspan.com/improved_persistent_login_cookie_best_practice
 *         and
http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/
 */
class PlgAuthenticationCookie extends JPlugin
{
	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 * @since  3.2
	 */
	protected $app;

	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 * @since  3.2
	 */
	protected $db;

	/**
	 * Reports the privacy related capabilities for this plugin to site
administrators.
	 *
	 * @return  array
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCollectAdminCapabilities()
	{
		$this->loadLanguage();

		return array(
			JText::_('PLG_AUTHENTICATION_COOKIE') => array(
				JText::_('PLG_AUTH_COOKIE_PRIVACY_CAPABILITY_COOKIE'),
			)
		);
	}

	/**
	 * This method should handle any authentication and report back to the
subject
	 *
	 * @param   array   $credentials  Array holding the user credentials
	 * @param   array   $options      Array of extra options
	 * @param   object  &$response    Authentication response object
	 *
	 * @return  boolean
	 *
	 * @since   3.2
	 */
	public function onUserAuthenticate($credentials, $options, &$response)
	{
		// No remember me for admin
		if ($this->app->isClient('administrator'))
		{
			return false;
		}

		// Get cookie
		$cookieName  = 'joomla_remember_me_' .
JUserHelper::getShortHashedUserAgent();
		$cookieValue = $this->app->input->cookie->get($cookieName);

		// Try with old cookieName (pre 3.6.0) if not found
		if (!$cookieValue)
		{
			$cookieName  = JUserHelper::getShortHashedUserAgent();
			$cookieValue = $this->app->input->cookie->get($cookieName);
		}

		if (!$cookieValue)
		{
			return false;
		}

		$cookieArray = explode('.', $cookieValue);

		// Check for valid cookie value
		if (count($cookieArray) !== 2)
		{
			// Destroy the cookie in the browser.
			$this->app->input->cookie->set($cookieName, '', 1,
$this->app->get('cookie_path', '/'),
$this->app->get('cookie_domain', ''));
			JLog::add('Invalid cookie detected.', JLog::WARNING,
'error');

			return false;
		}

		$response->type = 'Cookie';

		// Filter series since we're going to use it in the query
		$filter = new JFilterInput;
		$series = $filter->clean($cookieArray[1], 'ALNUM');

		// Remove expired tokens
		$query = $this->db->getQuery(true)
			->delete('#__user_keys')
			->where($this->db->quoteName('time') . ' <
' . $this->db->quote(time()));

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			// We aren't concerned with errors from this query, carry on
		}

		// Find the matching record if it exists.
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('user_id',
'token', 'series', 'time')))
			->from($this->db->quoteName('#__user_keys'))
			->where($this->db->quoteName('series') . ' =
' . $this->db->quote($series))
			->where($this->db->quoteName('uastring') . ' =
' . $this->db->quote($cookieName))
			->order($this->db->quoteName('time') . '
DESC');

		try
		{
			$results = $this->db->setQuery($query)->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$response->status = JAuthentication::STATUS_FAILURE;

			return false;
		}

		if (count($results) !== 1)
		{
			// Destroy the cookie in the browser.
			$this->app->input->cookie->set($cookieName, '', 1,
$this->app->get('cookie_path', '/'),
$this->app->get('cookie_domain', ''));
			$response->status = JAuthentication::STATUS_FAILURE;

			return false;
		}

		// We have a user with one cookie with a valid series and a corresponding
record in the database.
		if (!JUserHelper::verifyPassword($cookieArray[0], $results[0]->token))
		{
			/*
			 * This is a real attack!
			 * Either the series was guessed correctly or a cookie was stolen and
used twice (once by attacker and once by victim).
			 * Delete all tokens for this user!
			 */
			$query = $this->db->getQuery(true)
				->delete('#__user_keys')
				->where($this->db->quoteName('user_id') . ' =
' . $this->db->quote($results[0]->user_id));

			try
			{
				$this->db->setQuery($query)->execute();
			}
			catch (RuntimeException $e)
			{
				// Log an alert for the site admin
				JLog::add(
					sprintf('Failed to delete cookie token for user %s with the
following error: %s', $results[0]->user_id, $e->getMessage()),
					JLog::WARNING,
					'security'
				);
			}

			// Destroy the cookie in the browser.
			$this->app->input->cookie->set($cookieName, '', 1,
$this->app->get('cookie_path', '/'),
$this->app->get('cookie_domain', ''));

			// Issue warning by email to user and/or admin?
			JLog::add(JText::sprintf('PLG_AUTH_COOKIE_ERROR_LOG_LOGIN_FAILED',
$results[0]->user_id), JLog::WARNING, 'security');
			$response->status = JAuthentication::STATUS_FAILURE;

			return false;
		}

		// Make sure there really is a user with this name and get the data for
the session.
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('id',
'username', 'password')))
			->from($this->db->quoteName('#__users'))
			->where($this->db->quoteName('username') . ' =
' . $this->db->quote($results[0]->user_id))
			->where($this->db->quoteName('requireReset') . '
= 0');

		try
		{
			$result = $this->db->setQuery($query)->loadObject();
		}
		catch (RuntimeException $e)
		{
			$response->status = JAuthentication::STATUS_FAILURE;

			return false;
		}

		if ($result)
		{
			// Bring this in line with the rest of the system
			$user = JUser::getInstance($result->id);

			// Set response data.
			$response->username = $result->username;
			$response->email    = $user->email;
			$response->fullname = $user->name;
			$response->password = $result->password;
			$response->language = $user->getParam('language');

			// Set response status.
			$response->status        = JAuthentication::STATUS_SUCCESS;
			$response->error_message = '';
		}
		else
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message =
JText::_('JGLOBAL_AUTH_NO_USER');
		}
	}

	/**
	 * We set the authentication cookie only after login is successfully
finished.
	 * We set a new cookie either for a user with no cookies or one
	 * where the user used a cookie to authenticate.
	 *
	 * @param   array  $options  Array holding options
	 *
	 * @return  boolean  True on success
	 *
	 * @since   3.2
	 */
	public function onUserAfterLogin($options)
	{
		// No remember me for admin
		if ($this->app->isClient('administrator'))
		{
			return false;
		}

		if (isset($options['responseType']) &&
$options['responseType'] === 'Cookie')
		{
			// Logged in using a cookie
			$cookieName = 'joomla_remember_me_' .
JUserHelper::getShortHashedUserAgent();

			// We need the old data to get the existing series
			$cookieValue = $this->app->input->cookie->get($cookieName);

			// Try with old cookieName (pre 3.6.0) if not found
			if (!$cookieValue)
			{
				$oldCookieName = JUserHelper::getShortHashedUserAgent();
				$cookieValue   =
$this->app->input->cookie->get($oldCookieName);

				// Destroy the old cookie in the browser
				$this->app->input->cookie->set($oldCookieName,
'', 1, $this->app->get('cookie_path',
'/'), $this->app->get('cookie_domain',
''));
			}

			$cookieArray = explode('.', $cookieValue);

			// Filter series since we're going to use it in the query
			$filter = new JFilterInput;
			$series = $filter->clean($cookieArray[1], 'ALNUM');
		}
		elseif (!empty($options['remember']))
		{
			// Remember checkbox is set
			$cookieName = 'joomla_remember_me_' .
JUserHelper::getShortHashedUserAgent();

			// Create a unique series which will be used over the lifespan of the
cookie
			$unique     = false;
			$errorCount = 0;

			do
			{
				$series = JUserHelper::genRandomPassword(20);
				$query  = $this->db->getQuery(true)
					->select($this->db->quoteName('series'))
					->from($this->db->quoteName('#__user_keys'))
					->where($this->db->quoteName('series') . ' =
' . $this->db->quote($series));

				try
				{
					$results = $this->db->setQuery($query)->loadResult();

					if ($results === null)
					{
						$unique = true;
					}
				}
				catch (RuntimeException $e)
				{
					$errorCount++;

					// We'll let this query fail up to 5 times before giving up,
there's probably a bigger issue at this point
					if ($errorCount === 5)
					{
						return false;
					}
				}
			}

			while ($unique === false);
		}
		else
		{
			return false;
		}

		// Get the parameter values
		$lifetime = $this->params->get('cookie_lifetime', 60) *
24 * 60 * 60;
		$length   = $this->params->get('key_length', 16);

		// Generate new cookie
		$token       = JUserHelper::genRandomPassword($length);
		$cookieValue = $token . '.' . $series;

		// Overwrite existing cookie with new value
		$this->app->input->cookie->set(
			$cookieName,
			$cookieValue,
			time() + $lifetime,
			$this->app->get('cookie_path', '/'),
			$this->app->get('cookie_domain', ''),
			$this->app->isHttpsForced(),
			true
		);

		$query = $this->db->getQuery(true);

		if (!empty($options['remember']))
		{
			// Create new record
			$query
				->insert($this->db->quoteName('#__user_keys'))
				->set($this->db->quoteName('user_id') . ' =
' . $this->db->quote($options['user']->username))
				->set($this->db->quoteName('series') . ' =
' . $this->db->quote($series))
				->set($this->db->quoteName('uastring') . ' =
' . $this->db->quote($cookieName))
				->set($this->db->quoteName('time') . ' = '
. (time() + $lifetime));
		}
		else
		{
			// Update existing record with new token
			$query
				->update($this->db->quoteName('#__user_keys'))
				->where($this->db->quoteName('user_id') . ' =
' . $this->db->quote($options['user']->username))
				->where($this->db->quoteName('series') . ' =
' . $this->db->quote($series))
				->where($this->db->quoteName('uastring') . ' =
' . $this->db->quote($cookieName));
		}

		$hashedToken = JUserHelper::hashPassword($token);

		$query->set($this->db->quoteName('token') . ' =
' . $this->db->quote($hashedToken));

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * This is where we delete any authentication cookie when a user logs out
	 *
	 * @param   array  $options  Array holding options (length,
timeToExpiration)
	 *
	 * @return  boolean  True on success
	 *
	 * @since   3.2
	 */
	public function onUserAfterLogout($options)
	{
		// No remember me for admin
		if ($this->app->isClient('administrator'))
		{
			return false;
		}

		$cookieName  = 'joomla_remember_me_' .
JUserHelper::getShortHashedUserAgent();
		$cookieValue = $this->app->input->cookie->get($cookieName);

		// There are no cookies to delete.
		if (!$cookieValue)
		{
			return true;
		}

		$cookieArray = explode('.', $cookieValue);

		// Filter series since we're going to use it in the query
		$filter = new JFilterInput;
		$series = $filter->clean($cookieArray[1], 'ALNUM');

		// Remove the record from the database
		$query = $this->db->getQuery(true)
			->delete('#__user_keys')
			->where($this->db->quoteName('series') . ' =
' . $this->db->quote($series));

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			// We aren't concerned with errors from this query, carry on
		}

		// Destroy the cookie
		$this->app->input->cookie->set($cookieName, '', 1,
$this->app->get('cookie_path', '/'),
$this->app->get('cookie_domain', ''));

		return true;
	}
}
authentication/cookie/cookie.xml000064400000002772147357022230013044
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin"
group="authentication" method="upgrade">
	<name>plg_authentication_cookie</name>
	<author>Joomla! Project</author>
	<creationDate>July 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_AUTH_COOKIE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="cookie">cookie.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_authentication_cookie.ini</language>
		<language
tag="en-GB">en-GB.plg_authentication_cookie.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="cookie_lifetime"
					type="number"
					label="PLG_AUTH_COOKIE_FIELD_COOKIE_LIFETIME_LABEL"
					description="PLG_AUTH_COOKIE_FIELD_COOKIE_LIFETIME_DESC"
					default="60"
					filter="integer"
					required="true"
				/>

				<field
					name="key_length"
					type="list"
					label="PLG_AUTH_COOKIE_FIELD_KEY_LENGTH_LABEL"
					description="PLG_AUTH_COOKIE_FIELD_KEY_LENGTH_DESC"
					default="16"
					filter="integer"
					required="true"
					>
					<option value="8">8</option>
					<option value="16">16</option>
					<option value="32">32</option>
					<option value="64">64</option>
				</field>

			</fieldset>
		</fields>
	</config>
</extension>
authentication/gmail/gmail.php000064400000014535147357022230012473
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Authentication.gmail
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Authentication\AuthenticationResponse;
use Joomla\Registry\Registry;

/**
 * GMail Authentication Plugin
 *
 * @since  1.5
 */
class PlgAuthenticationGMail extends JPlugin
{
	/**
	 * This method should handle any authentication and report back to the
subject
	 *
	 * @param   array                   $credentials  Array holding the user
credentials
	 * @param   array                   $options      Array of extra options
	 * @param   AuthenticationResponse  &$response    Authentication
response object
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onUserAuthenticate($credentials, $options, &$response)
	{
		// Load plugin language
		$this->loadLanguage();

		// No backend authentication
		if (JFactory::getApplication()->isClient('administrator')
&& !$this->params->get('backendLogin', 0))
		{
			return;
		}

		$success = false;

		$curlParams = array(
			'follow_location' => true,
			'transport.curl'  => array(
				CURLOPT_SSL_VERIFYPEER =>
$this->params->get('verifypeer', 1)
			),
		);

		$transportParams = new Registry($curlParams);

		try
		{
			$http = JHttpFactory::getHttp($transportParams, 'curl');
		}
		catch (RuntimeException $e)
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->type          = 'GMail';
			$response->error_message =
JText::sprintf('JGLOBAL_AUTH_FAILED',
JText::_('JGLOBAL_AUTH_CURL_NOT_INSTALLED'));

			return;
		}

		// Check if we have a username and password
		if ($credentials['username'] === '' ||
$credentials['password'] === '')
		{
			$response->type          = 'GMail';
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message =
JText::sprintf('JGLOBAL_AUTH_FAILED',
JText::_('JGLOBAL_AUTH_USER_BLACKLISTED'));

			return;
		}

		$blacklist = explode(',',
$this->params->get('user_blacklist', ''));

		// Check if the username isn't blacklisted
		if (in_array($credentials['username'], $blacklist))
		{
			$response->type          = 'GMail';
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message =
JText::sprintf('JGLOBAL_AUTH_FAILED',
JText::_('JGLOBAL_AUTH_USER_BLACKLISTED'));

			return;
		}

		$suffix      = $this->params->get('suffix',
'');
		$applysuffix = $this->params->get('applysuffix', 0);
		$offset      = strpos($credentials['username'], '@');

		// Check if we want to do suffix stuff, typically for Google Apps for
Your Domain
		if ($suffix && $applysuffix)
		{
			if ($applysuffix == 1 && $offset === false)
			{
				// Apply suffix if missing
				$credentials['username'] .= '@' . $suffix;
			}
			elseif ($applysuffix == 2)
			{
				// Always use suffix
				if ($offset)
				{
					// If we already have an @, get rid of it and replace it
					$credentials['username'] =
substr($credentials['username'], 0, $offset);
				}

				$credentials['username'] .= '@' . $suffix;
			}
		}

		$headers = array(
			'Authorization' => 'Basic ' .
base64_encode($credentials['username'] . ':' .
$credentials['password'])
		);

		try
		{
			$result =
$http->get('https://mail.google.com/mail/feed/atom',
$headers);
		}
		catch (Exception $e)
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->type          = 'GMail';
			$response->error_message =
JText::sprintf('JGLOBAL_AUTH_FAILED',
JText::_('JGLOBAL_AUTH_UNKNOWN_ACCESS_DENIED'));

			return;
		}

		$code = $result->code;

		switch ($code)
		{
			case 200 :
				$message = JText::_('JGLOBAL_AUTH_ACCESS_GRANTED');
				$success = true;
				break;

			case 401 :
				$message = JText::_('JGLOBAL_AUTH_ACCESS_DENIED');
				break;

			default :
				$message = JText::_('JGLOBAL_AUTH_UNKNOWN_ACCESS_DENIED');
				break;
		}

		$response->type = 'GMail';

		if (!$success)
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message =
JText::sprintf('JGLOBAL_AUTH_FAILED', $message);

			return;
		}

		if (strpos($credentials['username'], '@') === false)
		{
			if ($suffix)
			{
				// If there is a suffix then we want to apply it
				$email = $credentials['username'] . '@' . $suffix;
			}
			else
			{
				// If there isn't a suffix just use the default gmail one
				$email = $credentials['username'] . '@gmail.com';
			}
		}
		else
		{
			// The username looks like an email address (probably is) so use that
			$email = $credentials['username'];
		}

		// Extra security checks with existing local accounts
		$db                  = JFactory::getDbo();
		$localUsernameChecks = array(strstr($email, '@', true),
$email);

		$query = $db->getQuery(true)
			->select('id, activation, username, email, block')
			->from('#__users')
			->where('username IN(' . implode(',',
array_map(array($db, 'quote'), $localUsernameChecks)) .
')'
				. ' OR email = ' . $db->quote($email)
			);

		$db->setQuery($query);

		if ($localUsers = $db->loadObjectList())
		{
			foreach ($localUsers as $localUser)
			{
				// Local user exists with same username but different email address
				if ($email !== $localUser->email)
				{
					$response->status        = JAuthentication::STATUS_FAILURE;
					$response->error_message =
JText::sprintf('JGLOBAL_AUTH_FAILED',
JText::_('PLG_GMAIL_ERROR_LOCAL_USERNAME_CONFLICT'));

					return;
				}
				else
				{
					// Existing user disabled locally
					if ($localUser->block || !empty($localUser->activation))
					{
						$response->status        = JAuthentication::STATUS_FAILURE;
						$response->error_message =
JText::_('JGLOBAL_AUTH_ACCESS_DENIED');

						return;
					}

					// We will always keep the local username for existing accounts
					$credentials['username'] = $localUser->username;

					break;
				}
			}
		}
		elseif
(JFactory::getApplication()->isClient('administrator'))
		{
			// We wont' allow backend access without local account
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message = JText::_('JERROR_LOGIN_DENIED');

			return;
		}

		$response->status        = JAuthentication::STATUS_SUCCESS;
		$response->error_message = '';
		$response->email         = $email;

		// Reset the username to what we ended up using
		$response->username = $credentials['username'];
		$response->fullname = $credentials['username'];
	}
}
authentication/gmail/gmail.xml000064400000004454147357022230012503
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="authentication" method="upgrade">
	<name>plg_authentication_gmail</name>
	<author>Joomla! Project</author>
	<creationDate>February 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_GMAIL_XML_DESCRIPTION</description>
	<files>
		<filename plugin="gmail">gmail.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_authentication_gmail.ini</language>
		<language
tag="en-GB">en-GB.plg_authentication_gmail.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="applysuffix"
					type="list"
					label="PLG_GMAIL_FIELD_APPLYSUFFIX_LABEL"
					description="PLG_GMAIL_FIELD_APPLYSUFFIX_DESC"
					default="0"
					filter="integer"
					>
					<option
value="0">PLG_GMAIL_FIELD_VALUE_NOAPPLYSUFFIX</option>
					<option
value="1">PLG_GMAIL_FIELD_VALUE_APPLYSUFFIXMISSING</option>
					<option
value="2">PLG_GMAIL_FIELD_VALUE_APPLYSUFFIXALWAYS</option>
				</field>

				<field
					name="suffix"
					type="text"
					label="PLG_GMAIL_FIELD_SUFFIX_LABEL"
					description="PLG_GMAIL_FIELD_SUFFIX_DESC"
					size="20"
					showon="applysuffix:1,2"
				/>

				<field
					name="verifypeer"
					type="radio"
					label="PLG_GMAIL_FIELD_VERIFYPEER_LABEL"
					description="PLG_GMAIL_FIELD_VERIFYPEER_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="user_blacklist"
					type="text"
					label="PLG_GMAIL_FIELD_USER_BLACKLIST_LABEL"
					description="PLG_GMAIL_FIELD_USER_BLACKLIST_DESC"
					size="20"
				/>

				<field
					name="backendLogin"
					type="radio"
					label="PLG_GMAIL_FIELD_BACKEND_LOGIN_LABEL"
					description="PLG_GMAIL_FIELD_BACKEND_LOGIN_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JENABLED</option>
					<option value="0">JDISABLED</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
authentication/joomla/joomla.php000064400000013766147357022230013060
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Authentication.joomla
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla Authentication plugin
 *
 * @since  1.5
 */
class PlgAuthenticationJoomla extends JPlugin
{
	/**
	 * This method should handle any authentication and report back to the
subject
	 *
	 * @param   array   $credentials  Array holding the user credentials
	 * @param   array   $options      Array of extra options
	 * @param   object  &$response    Authentication response object
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onUserAuthenticate($credentials, $options, &$response)
	{
		$response->type = 'Joomla';

		// Joomla does not like blank passwords
		if (empty($credentials['password']))
		{
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message =
JText::_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');

			return;
		}

		// Get a database object
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select('id, password')
			->from('#__users')
			->where('username=' .
$db->quote($credentials['username']));

		$db->setQuery($query);
		$result = $db->loadObject();

		if ($result)
		{
			$match = JUserHelper::verifyPassword($credentials['password'],
$result->password, $result->id);

			if ($match === true)
			{
				// Bring this in line with the rest of the system
				$user               = JUser::getInstance($result->id);
				$response->email    = $user->email;
				$response->fullname = $user->name;

				if (JFactory::getApplication()->isClient('administrator'))
				{
					$response->language =
$user->getParam('admin_language');
				}
				else
				{
					$response->language = $user->getParam('language');
				}

				$response->status        = JAuthentication::STATUS_SUCCESS;
				$response->error_message = '';
			}
			else
			{
				// Invalid password
				$response->status        = JAuthentication::STATUS_FAILURE;
				$response->error_message =
JText::_('JGLOBAL_AUTH_INVALID_PASS');
			}
		}
		else
		{
			// Let's hash the entered password even if we don't have a
matching user for some extra response time
			// By doing so, we mitigate side channel user enumeration attacks
			JUserHelper::hashPassword($credentials['password']);

			// Invalid user
			$response->status        = JAuthentication::STATUS_FAILURE;
			$response->error_message =
JText::_('JGLOBAL_AUTH_NO_USER');
		}

		// Check the two factor authentication
		if ($response->status === JAuthentication::STATUS_SUCCESS)
		{
			$methods = JAuthenticationHelper::getTwoFactorMethods();

			if (count($methods) <= 1)
			{
				// No two factor authentication method is enabled
				return;
			}

			JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_users/models', 'UsersModel');

			/** @var UsersModelUser $model */
			$model = JModelLegacy::getInstance('User',
'UsersModel', array('ignore_request' => true));

			// Load the user's OTP (one time password, a.k.a. two factor auth)
configuration
			if (!array_key_exists('otp_config', $options))
			{
				$otpConfig             = $model->getOtpConfig($result->id);
				$options['otp_config'] = $otpConfig;
			}
			else
			{
				$otpConfig = $options['otp_config'];
			}

			// Check if the user has enabled two factor authentication
			if (empty($otpConfig->method) || ($otpConfig->method ===
'none'))
			{
				// Warn the user if they are using a secret code but they have not
				// enabled two factor auth in their account.
				if (!empty($credentials['secretkey']))
				{
					try
					{
						$app = JFactory::getApplication();

						$this->loadLanguage();

						$app->enqueueMessage(JText::_('PLG_AUTH_JOOMLA_ERR_SECRET_CODE_WITHOUT_TFA'),
'warning');
					}
					catch (Exception $exc)
					{
						// This happens when we are in CLI mode. In this case
						// no warning is issued
						return;
					}
				}

				return;
			}

			// Try to validate the OTP
			FOFPlatform::getInstance()->importPlugin('twofactorauth');

			$otpAuthReplies =
FOFPlatform::getInstance()->runPlugins('onUserTwofactorAuthenticate',
array($credentials, $options));

			$check = false;

			/*
			 * This looks like noob code but DO NOT TOUCH IT and do not convert
			 * to in_array(). During testing in_array() inexplicably returned
			 * null when the OTEP begins with a zero! o_O
			 */
			if (!empty($otpAuthReplies))
			{
				foreach ($otpAuthReplies as $authReply)
				{
					$check = $check || $authReply;
				}
			}

			// Fall back to one time emergency passwords
			if (!$check)
			{
				// Did the user use an OTEP instead?
				if (empty($otpConfig->otep))
				{
					if (empty($otpConfig->method) || ($otpConfig->method ===
'none'))
					{
						// Two factor authentication is not enabled on this account.
						// Any string is assumed to be a valid OTEP.

						return;
					}
					else
					{
						/*
						 * Two factor authentication enabled and no OTEPs defined. The
						 * user has used them all up. Therefore anything they enter is
						 * an invalid OTEP.
						 */
						$response->status        = JAuthentication::STATUS_FAILURE;
						$response->error_message =
JText::_('JGLOBAL_AUTH_INVALID_SECRETKEY');

						return;
					}
				}

				// Clean up the OTEP (remove dashes, spaces and other funny stuff
				// our beloved users may have unwittingly stuffed in it)
				$otep  = $credentials['secretkey'];
				$otep  = filter_var($otep, FILTER_SANITIZE_NUMBER_INT);
				$otep  = str_replace('-', '', $otep);
				$check = false;

				// Did we find a valid OTEP?
				if (in_array($otep, $otpConfig->otep))
				{
					// Remove the OTEP from the array
					$otpConfig->otep = array_diff($otpConfig->otep, array($otep));

					$model->setOtpConfig($result->id, $otpConfig);

					// Return true; the OTEP was a valid one
					$check = true;
				}
			}

			if (!$check)
			{
				$response->status        = JAuthentication::STATUS_FAILURE;
				$response->error_message =
JText::_('JGLOBAL_AUTH_INVALID_SECRETKEY');
			}
		}
	}
}
authentication/joomla/joomla.xml000064400000001444147357022230013057
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="authentication" method="upgrade">
	<name>plg_authentication_joomla</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_AUTH_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_authentication_joomla.ini</language>
		<language
tag="en-GB">en-GB.plg_authentication_joomla.sys.ini</language>
	</languages>
</extension>
authentication/ldap/ldap.php000064400000011767147357022230012155
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Authentication.ldap
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Ldap\LdapClient;

/**
 * LDAP Authentication Plugin
 *
 * @since  1.5
 */
class PlgAuthenticationLdap extends JPlugin
{
	/**
	 * This method should handle any authentication and report back to the
subject
	 *
	 * @param   array   $credentials  Array holding the user credentials
	 * @param   array   $options      Array of extra options
	 * @param   object  &$response    Authentication response object
	 *
	 * @return  boolean
	 *
	 * @since   1.5
	 */
	public function onUserAuthenticate($credentials, $options, &$response)
	{
		$userdetails = null;
		$success = 0;
		$userdetails = array();

		// For JLog
		$response->type = 'LDAP';

		// Strip null bytes from the password
		$credentials['password'] = str_replace(chr(0), '',
$credentials['password']);

		// LDAP does not like Blank passwords (tries to Anon Bind which is bad)
		if (empty($credentials['password']))
		{
			$response->status = JAuthentication::STATUS_FAILURE;
			$response->error_message =
JText::_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');

			return false;
		}

		// Load plugin params info
		$ldap_email    = $this->params->get('ldap_email');
		$ldap_fullname = $this->params->get('ldap_fullname');
		$ldap_uid      = $this->params->get('ldap_uid');
		$auth_method   = $this->params->get('auth_method');

		$ldap = new LdapClient($this->params);

		if (!$ldap->connect())
		{
			$response->status = JAuthentication::STATUS_FAILURE;
			$response->error_message =
JText::_('JGLOBAL_AUTH_NOT_CONNECT');

			return;
		}

		switch ($auth_method)
		{
			case 'search':
			{
				// Bind using Connect Username/password
				// Force anon bind to mitigate misconfiguration like [#7119]
				if ($this->params->get('username', '') !==
'')
				{
					$bindtest = $ldap->bind();
				}
				else
				{
					$bindtest = $ldap->anonymous_bind();
				}

				if ($bindtest)
				{
					// Search for users DN
					$binddata = $this->searchByString(
						str_replace(
							'[search]',
							str_replace(';', '\3b',
$ldap->escape($credentials['username'], null,
LDAP_ESCAPE_FILTER)),
							$this->params->get('search_string')
						),
						$ldap
					);

					if (isset($binddata[0], $binddata[0]['dn']))
					{
						// Verify Users Credentials
						$success = $ldap->bind($binddata[0]['dn'],
$credentials['password'], 1);

						// Get users details
						$userdetails = $binddata;
					}
					else
					{
						$response->status = JAuthentication::STATUS_FAILURE;
						$response->error_message =
JText::_('JGLOBAL_AUTH_NO_USER');
					}
				}
				else
				{
					$response->status = JAuthentication::STATUS_FAILURE;
					$response->error_message =
JText::_('JGLOBAL_AUTH_NOT_CONNECT');
				}
			}	break;

			case 'bind':
			{
				// We just accept the result here
				$success =
$ldap->bind($ldap->escape($credentials['username'], null,
LDAP_ESCAPE_DN), $credentials['password']);

				if ($success)
				{
					$userdetails = $this->searchByString(
						str_replace(
							'[search]',
							str_replace(';', '\3b',
$ldap->escape($credentials['username'], null,
LDAP_ESCAPE_FILTER)),
							$this->params->get('search_string')
						),
						$ldap
					);
				}
				else
				{
					$response->status = JAuthentication::STATUS_FAILURE;
					$response->error_message =
JText::_('JGLOBAL_AUTH_INVALID_PASS');
				}
			}	break;
		}

		if (!$success)
		{
			$response->status = JAuthentication::STATUS_FAILURE;

			if ($response->error_message === '')
			{
				$response->error_message =
JText::_('JGLOBAL_AUTH_INVALID_PASS');
			}
		}
		else
		{
			// Grab some details from LDAP and return them
			if (isset($userdetails[0][$ldap_uid][0]))
			{
				$response->username = $userdetails[0][$ldap_uid][0];
			}

			if (isset($userdetails[0][$ldap_email][0]))
			{
				$response->email = $userdetails[0][$ldap_email][0];
			}

			if (isset($userdetails[0][$ldap_fullname][0]))
			{
				$response->fullname = $userdetails[0][$ldap_fullname][0];
			}
			else
			{
				$response->fullname = $credentials['username'];
			}

			// Were good - So say so.
			$response->status        = JAuthentication::STATUS_SUCCESS;
			$response->error_message = '';
		}

		$ldap->close();
	}

	/**
	 * Shortcut method to build a LDAP search based on a semicolon separated
string
	 *
	 * Note that this method requires that semicolons which should be part of
the search term to be escaped
	 * to correctly split the search string into separate lookups
	 *
	 * @param   string      $search  search string of search values
	 * @param   LdapClient  $ldap    The LDAP client
	 *
	 * @return  array  Search results
	 *
	 * @since   3.8.2
	 */
	private static function searchByString($search, LdapClient $ldap)
	{
		$results = explode(';', $search);

		foreach ($results as $key => $result)
		{
			$results[$key] = '(' . str_replace('\3b',
';', $result) . ')';
		}

		return $ldap->search($results);
	}
}
authentication/ldap/ldap.xml000064400000010756147357022230012163
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="authentication" method="upgrade">
	<name>plg_authentication_ldap</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_LDAP_XML_DESCRIPTION</description>
	<files>
		<filename plugin="ldap">ldap.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_authentication_ldap.ini</language>
		<language
tag="en-GB">en-GB.plg_authentication_ldap.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="host"
					type="text"
					label="PLG_LDAP_FIELD_HOST_LABEL"
					description="PLG_LDAP_FIELD_HOST_DESC"
					size="20"
				/>

				<field
					name="port"
					type="number"
					label="PLG_LDAP_FIELD_PORT_LABEL"
					description="PLG_LDAP_FIELD_PORT_DESC"
					min="1"
					max="65535"
					default="389"
					hint="389"
					validate="number"
					filter="integer"
					size="5"
				/>

				<field
					name="use_ldapV3"
					type="radio"
					label="PLG_LDAP_FIELD_V3_LABEL"
					description="PLG_LDAP_FIELD_V3_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="negotiate_tls"
					type="radio"
					label="PLG_LDAP_FIELD_NEGOCIATE_LABEL"
					description="PLG_LDAP_FIELD_NEGOCIATE_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="ignore_reqcert_tls"
					type="radio"
					label="PLG_LDAP_FIELD_IGNORE_REQCERT_TLS_LABEL"
					description="PLG_LDAP_FIELD_IGNORE_REQCERT_TLS_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="no_referrals"
					type="radio"
					label="PLG_LDAP_FIELD_REFERRALS_LABEL"
					description="PLG_LDAP_FIELD_REFERRALS_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="auth_method"
					type="list"
					label="PLG_LDAP_FIELD_AUTHMETHOD_LABEL"
					description="PLG_LDAP_FIELD_AUTHMETHOD_DESC"
					default="bind"
					>
					<option
value="search">PLG_LDAP_FIELD_VALUE_BINDSEARCH</option>
					<option
value="bind">PLG_LDAP_FIELD_VALUE_BINDUSER</option>
				</field>

				<field
					name="base_dn"
					type="text"
					label="PLG_LDAP_FIELD_BASEDN_LABEL"
					description="PLG_LDAP_FIELD_BASEDN_DESC"
					size="20"
				/>

				<field
					name="search_string"
					type="text"
					label="PLG_LDAP_FIELD_SEARCHSTRING_LABEL"
					description="PLG_LDAP_FIELD_SEARCHSTRING_DESC"
					size="20"
				/>

				<field
					name="users_dn"
					type="text"
					label="PLG_LDAP_FIELD_USERSDN_LABEL"
					description="PLG_LDAP_FIELD_USERSDN_DESC"
					size="20"
				/>

				<field
					name="username"
					type="text"
					label="PLG_LDAP_FIELD_USERNAME_LABEL"
					description="PLG_LDAP_FIELD_USERNAME_DESC"
					size="20"
				/>

				<field
					name="password"
					type="password"
					label="PLG_LDAP_FIELD_PASSWORD_LABEL"
					description="PLG_LDAP_FIELD_PASSWORD_DESC"
					size="20"
				/>

				<field
					name="ldap_fullname"
					type="text"
					label="PLG_LDAP_FIELD_FULLNAME_LABEL"
					description="PLG_LDAP_FIELD_FULLNAME_DESC"
					default="fullName"
					size="20"
				/>

				<field
					name="ldap_email"
					type="text"
					label="PLG_LDAP_FIELD_EMAIL_LABEL"
					description="PLG_LDAP_FIELD_EMAIL_DESC"
					default="mail"
					size="20"
				/>

				<field
					name="ldap_uid"
					type="text"
					label="PLG_LDAP_FIELD_UID_LABEL"
					description="PLG_LDAP_FIELD_UID_DESC"
					default="uid"
					size="20"
				/>
				<field
					name="ldap_debug"
					type="radio"
					label="PLG_LDAP_FIELD_LDAPDEBUG_LABEL"
					description="PLG_LDAP_FIELD_LDAPDEBUG_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
captcha/recaptcha/postinstall/actions.php000064400000003026147357022230014634
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Captcha
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 *
 * This file contains the functions used by the com_postinstall code to
deliver
 * the necessary post-installation messages for the end of life of
reCAPTCHA V1.
 */

/**
 * Checks if the plugin is enabled and reCAPTCHA V1 is being used. If true
then the
 * message about reCAPTCHA v1 EOL should be displayed.
 *
 * @return  boolean
 *
 * @since  3.8.6
 */
function recaptcha_postinstall_condition()
{
	$db = JFactory::getDbo();

	$query = $db->getQuery(true)
		->select('1')
		->from($db->qn('#__extensions'))
		->where($db->qn('name') . ' = ' .
$db->q('plg_captcha_recaptcha'))
		->where($db->qn('enabled') . ' = 1')
		->where($db->qn('params') . ' LIKE ' .
$db->q('%1.0%'));
	$db->setQuery($query);
	$enabled_plugins = $db->loadObjectList();

	return count($enabled_plugins) === 1;
}

/**
 * Open the reCAPTCHA plugin so that they can update the settings to V2 and
new keys.
 *
 * @return  void
 *
 * @since   3.8.6
 */
function recaptcha_postinstall_action()
{
	$db = JFactory::getDbo();

	$query = $db->getQuery(true)
		->select('extension_id')
		->from($db->qn('#__extensions'))
		->where($db->qn('name') . ' = ' .
$db->q('plg_captcha_recaptcha'));
	$db->setQuery($query);
	$e_id = $db->loadResult();

	$url =
'index.php?option=com_plugins&task=plugin.edit&extension_id='
. $e_id;
	JFactory::getApplication()->redirect($url);
}
captcha/recaptcha/recaptcha.php000064400000023126147357022230012555
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Captcha
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Captcha\Google\HttpBridgePostRequestMethod;
use Joomla\Utilities\IpHelper;

/**
 * Recaptcha Plugin
 * Based on the official recaptcha library(
https://packagist.org/packages/google/recaptcha )
 *
 * @since  2.5
 */
class PlgCaptchaRecaptcha extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Reports the privacy related capabilities for this plugin to site
administrators.
	 *
	 * @return  array
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCollectAdminCapabilities()
	{
		$this->loadLanguage();

		return array(
			JText::_('PLG_CAPTCHA_RECAPTCHA') => array(
				JText::_('PLG_RECAPTCHA_PRIVACY_CAPABILITY_IP_ADDRESS'),
			)
		);
	}

	/**
	 * Initialise the captcha
	 *
	 * @param   string  $id  The id of the field.
	 *
	 * @return  Boolean	True on success, false otherwise
	 *
	 * @since   2.5
	 * @throws  \RuntimeException
	 */
	public function onInit($id = 'dynamic_recaptcha_1')
	{
		$pubkey = $this->params->get('public_key', '');

		if ($pubkey === '')
		{
			throw new
\RuntimeException(JText::_('PLG_RECAPTCHA_ERROR_NO_PUBLIC_KEY'));
		}

		if ($this->params->get('version', '1.0') ===
'1.0')
		{
			JHtml::_('jquery.framework');

			$theme  = $this->params->get('theme',
'clean');
			$file   =
'https://www.google.com/recaptcha/api/js/recaptcha_ajax.js';

			JHtml::_('script', $file);
			JFactory::getDocument()->addScriptDeclaration('jQuery( document
).ready(function()
				{Recaptcha.create("' . $pubkey . '", "' .
$id . '", {theme: "' . $theme . '",' .
$this->_getLanguage() . 'tabindex: 0});});');
		}
		else
		{
			// Load callback first for browser compatibility
			JHtml::_('script',
'plg_captcha_recaptcha/recaptcha.min.js',
array('version' => 'auto', 'relative'
=> true));

			$file =
'https://www.google.com/recaptcha/api.js?onload=JoomlaInitReCaptcha2&render=explicit&hl='
. JFactory::getLanguage()->getTag();
			JHtml::_('script', $file);
		}

		return true;
	}

	/**
	 * Gets the challenge HTML
	 *
	 * @param   string  $name   The name of the field. Not Used.
	 * @param   string  $id     The id of the field.
	 * @param   string  $class  The class of the field.
	 *
	 * @return  string  The HTML to be embedded in the form.
	 *
	 * @since  2.5
	 */
	public function onDisplay($name = null, $id =
'dynamic_recaptcha_1', $class = '')
	{
		$dom = new \DOMDocument('1.0', 'UTF-8');
		$ele = $dom->createElement('div');
		$ele->setAttribute('id', $id);

		if ($this->params->get('version', '1.0') ===
'1.0')
		{
			$ele->setAttribute('class', $class);
		}
		else
		{
			$ele->setAttribute('class', ((trim($class) == '')
? 'g-recaptcha' : ($class . ' g-recaptcha')));
			$ele->setAttribute('data-sitekey',
$this->params->get('public_key', ''));
			$ele->setAttribute('data-theme',
$this->params->get('theme2', 'light'));
			$ele->setAttribute('data-size',
$this->params->get('size', 'normal'));
			$ele->setAttribute('data-tabindex',
$this->params->get('tabindex', '0'));
			$ele->setAttribute('data-callback',
$this->params->get('callback', ''));
			$ele->setAttribute('data-expired-callback',
$this->params->get('expired_callback', ''));
			$ele->setAttribute('data-error-callback',
$this->params->get('error_callback', ''));
		}

		$dom->appendChild($ele);
		return $dom->saveHTML($ele);
	}

	/**
	 * Calls an HTTP POST function to verify if the user's guess was
correct
	 *
	 * @param   string  $code  Answer provided by user. Not needed for the
Recaptcha implementation
	 *
	 * @return  True if the answer is correct, false otherwise
	 *
	 * @since   2.5
	 * @throws  \RuntimeException
	 */
	public function onCheckAnswer($code = null)
	{
		$input      = \JFactory::getApplication()->input;
		$privatekey = $this->params->get('private_key');
		$version    = $this->params->get('version',
'1.0');
		$remoteip   = IpHelper::getIp();

		switch ($version)
		{
			case '1.0':
				$challenge = $input->get('recaptcha_challenge_field',
'', 'string');
				$response  = $code ? $code :
$input->get('recaptcha_response_field', '',
'string');
				$spam      = ($challenge === '' || $response ===
'');
				break;
			case '2.0':
				// Challenge Not needed in 2.0 but needed for getResponse call
				$challenge = null;
				$response  = $code ? $code :
$input->get('g-recaptcha-response', '',
'string');
				$spam      = ($response === '');
				break;
		}

		// Check for Private Key
		if (empty($privatekey))
		{
			throw new
\RuntimeException(JText::_('PLG_RECAPTCHA_ERROR_NO_PRIVATE_KEY'));
		}

		// Check for IP
		if (empty($remoteip))
		{
			throw new
\RuntimeException(JText::_('PLG_RECAPTCHA_ERROR_NO_IP'));
		}

		// Discard spam submissions
		if ($spam)
		{
			throw new
\RuntimeException(JText::_('PLG_RECAPTCHA_ERROR_EMPTY_SOLUTION'));
		}

		return $this->getResponse($privatekey, $remoteip, $response,
$challenge);
	}

	/**
	 * Get the reCaptcha response.
	 *
	 * @param   string  $privatekey  The private key for authentication.
	 * @param   string  $remoteip    The remote IP of the visitor.
	 * @param   string  $response    The response received from Google.
	 * @param   string  $challenge   The challenge field from the reCaptcha.
Only for 1.0
	 *
	 * @return bool True if response is good | False if response is bad.
	 *
	 * @since   3.4
	 * @throws  \RuntimeException
	 */
	private function getResponse($privatekey, $remoteip, $response, $challenge
= null)
	{
		$version = $this->params->get('version',
'1.0');

		switch ($version)
		{
			case '1.0':
				$response = $this->_recaptcha_http_post(
					'www.google.com', '/recaptcha/api/verify',
					array(
						'privatekey' => $privatekey,
						'remoteip'   => $remoteip,
						'challenge'  => $challenge,
						'response'   => $response
					)
				);

				$answers = explode("\n", $response[1]);

				if (trim($answers[0]) !== 'true')
				{
					// @todo use exceptions here
					$this->_subject->setError(JText::_('PLG_RECAPTCHA_ERROR_'
. strtoupper(str_replace('-', '_', $answers[1]))));

					return false;
				}
				break;
			case '2.0':
				$reCaptcha = new \ReCaptcha\ReCaptcha($privatekey, new
HttpBridgePostRequestMethod);
				$response = $reCaptcha->verify($response, $remoteip);

				if (!$response->isSuccess())
				{
					foreach ($response->getErrorCodes() as $error)
					{
						throw new \RuntimeException($error);
					}

					return false;
				}
				break;
		}

		return true;
	}

	/**
	 * Encodes the given data into a query string format.
	 *
	 * @param   array  $data  Array of string elements to be encoded
	 *
	 * @return  string  Encoded request
	 *
	 * @since  2.5
	 */
	private function _recaptcha_qsencode($data)
	{
		$req = '';

		foreach ($data as $key => $value)
		{
			$req .= $key . '=' . urlencode(stripslashes($value)) .
'&';
		}

		// Cut the last '&'
		$req = rtrim($req, '&');

		return $req;
	}

	/**
	 * Submits an HTTP POST to a reCAPTCHA server.
	 *
	 * @param   string  $host  Host name to POST to.
	 * @param   string  $path  Path on host to POST to.
	 * @param   array   $data  Data to be POSTed.
	 * @param   int     $port  Optional port number on host.
	 *
	 * @return  array   Response
	 *
	 * @since  2.5
	 */
	private function _recaptcha_http_post($host, $path, $data, $port = 80)
	{
		$req = $this->_recaptcha_qsencode($data);

		$http_request  = "POST $path HTTP/1.0\r\n";
		$http_request .= "Host: $host\r\n";
		$http_request .= "Content-Type:
application/x-www-form-urlencoded;\r\n";
		$http_request .= "Content-Length: " . strlen($req) .
"\r\n";
		$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
		$http_request .= "\r\n";
		$http_request .= $req;

		$response = '';

		if (($fs = @fsockopen($host, $port, $errno, $errstr, 10)) === false)
		{
			die('Could not open socket');
		}

		fwrite($fs, $http_request);

		while (!feof($fs))
		{
			// One TCP-IP packet
			$response .= fgets($fs, 1160);
		}

		fclose($fs);
		$response = explode("\r\n\r\n", $response, 2);

		return $response;
	}

	/**
	 * Get the language tag or a custom translation
	 *
	 * @return  string
	 *
	 * @since  2.5
	 */
	private function _getLanguage()
	{
		$language = JFactory::getLanguage();

		$tag = explode('-', $language->getTag());
		$tag = $tag[0];
		$available = array('en', 'pt', 'fr',
'de', 'nl', 'ru', 'es',
'tr');

		if (in_array($tag, $available))
		{
			return "lang : '" . $tag . "',";
		}

		// If the default language is not available, let's search for a
custom translation
		if ($language->hasKey('PLG_RECAPTCHA_CUSTOM_LANG'))
		{
			$custom[] = 'custom_translations : {';
			$custom[] = "\t" . 'instructions_visual : "' .
JText::_('PLG_RECAPTCHA_INSTRUCTIONS_VISUAL') .
'",';
			$custom[] = "\t" . 'instructions_audio : "' .
JText::_('PLG_RECAPTCHA_INSTRUCTIONS_AUDIO') .
'",';
			$custom[] = "\t" . 'play_again : "' .
JText::_('PLG_RECAPTCHA_PLAY_AGAIN') . '",';
			$custom[] = "\t" . 'cant_hear_this : "' .
JText::_('PLG_RECAPTCHA_CANT_HEAR_THIS') . '",';
			$custom[] = "\t" . 'visual_challenge : "' .
JText::_('PLG_RECAPTCHA_VISUAL_CHALLENGE') . '",';
			$custom[] = "\t" . 'audio_challenge : "' .
JText::_('PLG_RECAPTCHA_AUDIO_CHALLENGE') . '",';
			$custom[] = "\t" . 'refresh_btn : "' .
JText::_('PLG_RECAPTCHA_REFRESH_BTN') . '",';
			$custom[] = "\t" . 'help_btn : "' .
JText::_('PLG_RECAPTCHA_HELP_BTN') . '",';
			$custom[] = "\t" . 'incorrect_try_again : "' .
JText::_('PLG_RECAPTCHA_INCORRECT_TRY_AGAIN') .
'",';
			$custom[] = '},';
			$custom[] = "lang : '" . $tag . "',";

			return implode("\n", $custom);
		}

		// If nothing helps fall back to english
		return '';
	}
}
captcha/recaptcha/recaptcha.xml000064400000007423147357022230012570
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.4" type="plugin"
group="captcha" method="upgrade">
	<name>plg_captcha_recaptcha</name>
	<version>3.4.0</version>
	<creationDate>December 2011</creationDate>
	<author>Joomla! Project</author>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<description>PLG_CAPTCHA_RECAPTCHA_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="recaptcha">recaptcha.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_captcha_recaptcha.ini</language>
		<language
tag="en-GB">en-GB.plg_captcha_recaptcha.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="message"
					type="note"
					label="PLG_RECAPTCHA_VERSION_1_WARNING_LABEL"
					showon="version:1.0"
				/>

				<field
					name="version"
					type="list"
					label="PLG_RECAPTCHA_VERSION_LABEL"
					description="PLG_RECAPTCHA_VERSION_DESC"
					default="2.0"
					size="1"
					>
					<option
value="1.0">PLG_RECAPTCHA_VERSION_V1</option>
					<option
value="2.0">PLG_RECAPTCHA_VERSION_V2</option>
				</field>

				<field
					name="public_key"
					type="text"
					label="PLG_RECAPTCHA_PUBLIC_KEY_LABEL"
					description="PLG_RECAPTCHA_PUBLIC_KEY_DESC"
					default=""
					required="true"
					filter="string"
					size="100"
					class="input-xxlarge"
				/>

				<field
					name="private_key"
					type="text"
					label="PLG_RECAPTCHA_PRIVATE_KEY_LABEL"
					description="PLG_RECAPTCHA_PRIVATE_KEY_DESC"
					default=""
					required="true"
					filter="string"
					size="100"
					class="input-xxlarge"
				/>

				<field
					name="theme"
					type="list"
					label="PLG_RECAPTCHA_THEME_LABEL"
					description="PLG_RECAPTCHA_THEME_DESC"
					default="clean"
					showon="version:1.0"
					filter=""
					>
					<option
value="clean">PLG_RECAPTCHA_THEME_CLEAN</option>
					<option
value="white">PLG_RECAPTCHA_THEME_WHITE</option>
					<option
value="blackglass">PLG_RECAPTCHA_THEME_BLACKGLASS</option>
					<option
value="red">PLG_RECAPTCHA_THEME_RED</option>
				</field>

				<field
					name="theme2"
					type="list"
					label="PLG_RECAPTCHA_THEME_LABEL"
					description="PLG_RECAPTCHA_THEME_DESC"
					default="light"
					showon="version:2.0"
					filter=""
					>
					<option
value="light">PLG_RECAPTCHA_THEME_LIGHT</option>
					<option
value="dark">PLG_RECAPTCHA_THEME_DARK</option>
				</field>

				<field
					name="size"
					type="list"
					label="PLG_RECAPTCHA_SIZE_LABEL"
					description="PLG_RECAPTCHA_SIZE_DESC"
					default="normal"
					showon="version:2.0"
					filter=""
					>
					<option
value="normal">PLG_RECAPTCHA_THEME_NORMAL</option>
					<option
value="compact">PLG_RECAPTCHA_THEME_COMPACT</option>
				</field>

				<field
					name="tabindex"
					type="number"
					label="PLG_RECAPTCHA_TABINDEX_LABEL"
					description="PLG_RECAPTCHA_TABINDEX_DESC"
					default="0"
					showon="version:2.0"
					min="0"
				/>

				<field
					name="callback"
					type="text"
					label="PLG_RECAPTCHA_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_CALLBACK_DESC"
					default=""
					showon="version:2.0"
					filter="string"
				/>

				<field
					name="expired_callback"
					type="text"
					label="PLG_RECAPTCHA_EXPIRED_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_EXPIRED_CALLBACK_DESC"
					default=""
					showon="version:2.0"
					filter="string"
				/>

				<field
					name="error_callback"
					type="text"
					label="PLG_RECAPTCHA_ERROR_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_ERROR_CALLBACK_DESC"
					default=""
					showon="version:2.0"
					filter="string"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
captcha/recaptcha_invisible/recaptcha_invisible.php000064400000012704147357022230016665
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Captcha
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Captcha\Google\HttpBridgePostRequestMethod;
use Joomla\Utilities\IpHelper;

/**
 * Invisible reCAPTCHA Plugin.
 *
 * @since  3.9.0
 */
class PlgCaptchaRecaptcha_Invisible extends \JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Reports the privacy related capabilities for this plugin to site
administrators.
	 *
	 * @return  array
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCollectAdminCapabilities()
	{
		$this->loadLanguage();

		return array(
			JText::_('PLG_CAPTCHA_RECAPTCHA_INVISIBLE') => array(
				JText::_('PLG_RECAPTCHA_INVISIBLE_PRIVACY_CAPABILITY_IP_ADDRESS'),
			)
		);
	}

	/**
	 * Initialise the captcha
	 *
	 * @param   string  $id  The id of the field.
	 *
	 * @return  boolean	True on success, false otherwise
	 *
	 * @since   3.9.0
	 * @throws  \RuntimeException
	 */
	public function onInit($id = 'dynamic_recaptcha_invisible_1')
	{
		$pubkey = $this->params->get('public_key', '');

		if ($pubkey === '')
		{
			throw new
\RuntimeException(JText::_('PLG_RECAPTCHA_INVISIBLE_ERROR_NO_PUBLIC_KEY'));
		}

		// Load callback first for browser compatibility
		\JHtml::_(
			'script',
			'plg_captcha_recaptcha_invisible/recaptcha.min.js',
			array('version' => 'auto', 'relative'
=> true),
			array('async' => 'async', 'defer' =>
'defer')
		);

		// Load Google reCAPTCHA api js
		$file = 'https://www.google.com/recaptcha/api.js'
			. '?onload=JoomlaInitReCaptchaInvisible'
			. '&render=explicit'
			. '&hl=' . \JFactory::getLanguage()->getTag();
		\JHtml::_(
			'script',
			$file,
			array(),
			array('async' => 'async', 'defer' =>
'defer')
		);

		return true;
	}

	/**
	 * Gets the challenge HTML
	 *
	 * @param   string  $name   The name of the field. Not Used.
	 * @param   string  $id     The id of the field.
	 * @param   string  $class  The class of the field.
	 *
	 * @return  string  The HTML to be embedded in the form.
	 *
	 * @since  3.9.0
	 */
	public function onDisplay($name = null, $id =
'dynamic_recaptcha_invisible_1', $class = '')
	{
		$dom = new \DOMDocument('1.0', 'UTF-8');
		$ele = $dom->createElement('div');
		$ele->setAttribute('id', $id);
		$ele->setAttribute('class', ((trim($class) == '')
? 'g-recaptcha' : ($class . ' g-recaptcha')));
		$ele->setAttribute('data-sitekey',
$this->params->get('public_key', ''));
		$ele->setAttribute('data-badge',
$this->params->get('badge', 'bottomright'));
		$ele->setAttribute('data-size', 'invisible');
		$ele->setAttribute('data-tabindex',
$this->params->get('tabindex', '0'));
		$ele->setAttribute('data-callback',
$this->params->get('callback', ''));
		$ele->setAttribute('data-expired-callback',
$this->params->get('expired_callback', ''));
		$ele->setAttribute('data-error-callback',
$this->params->get('error_callback', ''));
		$dom->appendChild($ele);

		return $dom->saveHTML($ele);
	}

	/**
	 * Calls an HTTP POST function to verify if the user's guess was
correct
	 *
	 * @param   string  $code  Answer provided by user. Not needed for the
Recaptcha implementation
	 *
	 * @return  boolean  True if the answer is correct, false otherwise
	 *
	 * @since   3.9.0
	 * @throws  \RuntimeException
	 */
	public function onCheckAnswer($code = null)
	{
		$input      = \JFactory::getApplication()->input;
		$privatekey = $this->params->get('private_key');
		$remoteip   = IpHelper::getIp();

		$response  = $input->get('g-recaptcha-response',
'', 'string');

		// Check for Private Key
		if (empty($privatekey))
		{
			throw new
\RuntimeException(JText::_('PLG_RECAPTCHA_INVISIBLE_ERROR_NO_PRIVATE_KEY'));
		}

		// Check for IP
		if (empty($remoteip))
		{
			throw new
\RuntimeException(JText::_('PLG_RECAPTCHA_INVISIBLE_ERROR_NO_IP'));
		}

		// Discard spam submissions
		if (trim($response) == '')
		{
			throw new
\RuntimeException(JText::_('PLG_RECAPTCHA_INVISIBLE_ERROR_EMPTY_SOLUTION'));
		}

		return $this->getResponse($privatekey, $remoteip, $response);
	}

	/**
	 * Method to react on the setup of a captcha field. Gives the possibility
	 * to change the field and/or the XML element for the field.
	 *
	 * @param   \Joomla\CMS\Form\Field\CaptchaField  $field    Captcha field
instance
	 * @param   \SimpleXMLElement                    $element  XML form
definition
	 *
	 * @return void
	 *
	 * @since 3.9.0
	 */
	public function onSetupField(\Joomla\CMS\Form\Field\CaptchaField $field,
\SimpleXMLElement $element)
	{
		// Hide the label for the invisible recaptcha type
		$element['hiddenLabel'] = true;
	}

	/**
	 * Get the reCaptcha response.
	 *
	 * @param   string  $privatekey  The private key for authentication.
	 * @param   string  $remoteip    The remote IP of the visitor.
	 * @param   string  $response    The response received from Google.
	 *
	 * @return  boolean  True if response is good | False if response is bad.
	 *
	 * @since   3.9.0
	 * @throws  \RuntimeException
	 */
	private function getResponse($privatekey, $remoteip, $response)
	{
		$reCaptcha = new \ReCaptcha\ReCaptcha($privatekey, new
HttpBridgePostRequestMethod);
		$response = $reCaptcha->verify($response, $remoteip);

		if (!$response->isSuccess())
		{
			foreach ($response->getErrorCodes() as $error)
			{
				throw new \RuntimeException($error);
			}

			return false;
		}

		return true;
	}
}
captcha/recaptcha_invisible/recaptcha_invisible.xml000064400000005374147357022230016703
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin"
group="captcha" method="upgrade">
	<name>plg_captcha_recaptcha_invisible</name>
	<version>3.8</version>
	<creationDate>November 2017</creationDate>
	<author>Joomla! Project</author>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<description>PLG_CAPTCHA_RECAPTCHA_INVISIBLE_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="recaptcha_invisible">recaptcha_invisible.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_captcha_recaptcha_invisible.ini</language>
		<language
tag="en-GB">en-GB.plg_captcha_recaptcha_invisible.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">

				<field
					name="public_key"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_PUBLIC_KEY_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_PUBLIC_KEY_DESC"
					default=""
					required="true"
					filter="string"
					size="100"
					class="input-xxlarge"
				/>

				<field
					name="private_key"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_PRIVATE_KEY_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_PRIVATE_KEY_DESC"
					default=""
					required="true"
					filter="string"
					size="100"
					class="input-xxlarge"
				/>

				<field
					name="badge"
					type="list"
					label="PLG_RECAPTCHA_INVISIBLE_BADGE_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_BADGE_DESC"
					default="bottomright"
					>
					<option
value="bottomright">PLG_RECAPTCHA_INVISIBLE_BADGE_BOTTOMRIGHT</option>
					<option
value="bottomleft">PLG_RECAPTCHA_INVISIBLE_BADGE_BOTTOMLEFT</option>
					<option
value="inline">PLG_RECAPTCHA_INVISIBLE_BADGE_INLINE</option>
				</field>

				<field
					name="tabindex"
					type="number"
					label="PLG_RECAPTCHA_INVISIBLE_TABINDEX_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_TABINDEX_DESC"
					default="0"
					min="0"
					filter="integer"
				/>

				<field
					name="callback"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_CALLBACK_DESC"
					default=""
					filter="string"
				/>

				<field
					name="expired_callback"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_EXPIRED_CALLBACK_DESC"
					default=""
					filter="string"
				/>

				<field
					name="error_callback"
					type="text"
					label="PLG_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_LABEL"
					description="PLG_RECAPTCHA_INVISIBLE_ERROR_CALLBACK_DESC"
					default=""
					filter="string"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
content/confirmconsent/confirmconsent.php000064400000003746147357022230015024
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.confirmconsent
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;

/**
 * The Joomla Core confirm consent plugin
 *
 * @since  3.9.0
 */
class PlgContentConfirmConsent extends CMSPlugin
{
	/**
	 * The Application object
	 *
	 * @var    JApplicationSite
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * The supported form contexts
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $supportedContext = array(
		'com_contact.contact',
		'com_mailto.mailto',
		'com_privacy.request',
	);

	/**
	 * Add additional fields to the supported forms
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareForm(JForm $form, $data)
	{
		if ($this->app->isClient('administrator') ||
!in_array($form->getName(), $this->supportedContext))
		{
			return true;
		}

		// Get the consent box Text & the selected privacyarticle
		$consentboxText  = (string)
$this->params->get('consentbox_text',
Text::_('PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_DEFAULT'));
		$privacyArticle  = $this->params->get('privacy_article',
false);

		$form->load('
			<form>
				<fieldset name="default"
addfieldpath="/plugins/content/confirmconsent/fields">
					<field
						name="consentbox"
						type="consentbox"
						articleid="' . $privacyArticle . '"
						label="PLG_CONTENT_CONFIRMCONSENT_CONSENTBOX_LABEL"
						required="true"
						>
						<option value="0">' .
htmlspecialchars($consentboxText, ENT_COMPAT, 'UTF-8') .
'</option>
					</field>
				</fieldset>
			</form>'
		);

		return true;
	}
}
content/confirmconsent/confirmconsent.xml000064400000003067147357022230015031
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="content" method="upgrade">
	<name>plg_content_confirmconsent</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_CONTENT_CONFIRMCONSENT_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="confirmconsent">confirmconsent.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_confirmconsent.ini</language>
		<language
tag="en-GB">en-GB.plg_content_confirmconsent.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic"
addfieldpath="/administrator/components/com_content/models/fields">
				<field
					name="consentbox_text"
					type="textarea"
					label="PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_LABEL"
					description="PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_DESC"
					hint="PLG_CONTENT_CONFIRMCONSENT_FIELD_NOTE_DEFAULT"
					class="span12"
					rows="7"
					cols="20"
					filter="html"
				/>

				<field
					name="privacy_article"
					type="modal_article"
					label="PLG_CONTENT_CONFIRMCONSENT_FIELD_ARTICLE_LABEL"
					description="PLG_CONTENT_CONFIRMCONSENT_FIELD_ARTICLE_DESC"
					select="true"
					new="true"
					edit="true"
					clear="true"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
content/confirmconsent/fields/consentbox.php000064400000015164147357022230015422
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.confirmconsent
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

JFormHelper::loadFieldClass('Checkboxes');

/**
 * Consentbox Field class for the Confirm Consent Plugin.
 *
 * @since  3.9.1
 */
class JFormFieldConsentBox extends JFormFieldCheckboxes
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.9.1
	 */
	protected $type = 'ConsentBox';

	/**
	 * Flag to tell the field to always be in multiple values mode.
	 *
	 * @var    boolean
	 * @since  3.9.1
	 */
	protected $forceMultiple = false;

	/**
	 * The article ID.
	 *
	 * @var    integer
	 * @since  3.9.1
	 */
	protected $articleid;

	/**
	 * Method to set certain otherwise inaccessible properties of the form
field object.
	 *
	 * @param   string  $name   The property name for which to set the value.
	 * @param   mixed   $value  The value of the property.
	 *
	 * @return  void
	 *
	 * @since   3.9.1
	 */
	public function __set($name, $value)
	{
		switch ($name)
		{
			case 'articleid':
				$this->articleid = (int) $value;
				break;

			default:
				parent::__set($name, $value);
		}
	}

	/**
	 * Method to get certain otherwise inaccessible properties from the form
field object.
	 *
	 * @param   string  $name  The property name for which to get the value.
	 *
	 * @return  mixed  The property value or null.
	 *
	 * @since   3.9.1
	 */
	public function __get($name)
	{
		switch ($name)
		{
			case 'articleid':
				return $this->$name;
		}

		return parent::__get($name);
	}

	/**
	 * Method to attach a JForm object to the field.
	 *
	 * @param   SimpleXMLElement  $element  The SimpleXMLElement object
representing the `<field>` tag for the form field object.
	 * @param   mixed             $value    The form field value to validate.
	 * @param   string            $group    The field name group control
value. This acts as an array container for the field.
	 *                                      For example if the field has
name="foo" and the group value is set to "bar" then the
	 *                                      full field name would end up being
"bar[foo]".
	 *
	 * @return  boolean  True on success.
	 *
	 * @see     JFormField::setup()
	 * @since   3.9.1
	 */
	public function setup(SimpleXMLElement $element, $value, $group = null)
	{
		$return = parent::setup($element, $value, $group);

		if ($return)
		{
			$this->articleid = (int) $this->element['articleid'];
		}

		return $return;
	}

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   3.9.1
	 */
	protected function getLabel()
	{
		if ($this->hidden)
		{
			return '';
		}

		$data = $this->getLayoutData();

		// Forcing the Alias field to display the tip below
		$position = $this->element['name'] == 'alias' ?
' data-placement="bottom" ' : '';

		// When we have an article let's add the modal and make the title
clickable
		if ($data['articleid'])
		{
			$attribs['data-toggle'] = 'modal';

			$data['label'] = HTMLHelper::_(
				'link',
				'#modal-' . $this->id,
				$data['label'],
				$attribs
			);
		}

		// Here mainly for B/C with old layouts. This can be done in the layouts
directly
		$extraData = array(
			'text'     => $data['label'],
			'for'      => $this->id,
			'classes'  => explode(' ',
$data['labelclass']),
			'position' => $position,
		);

		return
$this->getRenderer($this->renderLabelLayout)->render(array_merge($data,
$extraData));
	}

	/**
	 * Method to get the field input markup.
	 *
	 * @return  string  The field input markup.
	 *
	 * @since   3.9.2
	 */
	protected function getInput()
	{
		$modalHtml  = '';
		$layoutData = $this->getLayoutData();

		if ($this->articleid)
		{
			$modalParams['title']  = $layoutData['label'];
			$modalParams['url']    = $this->getAssignedArticleUrl();
			$modalParams['height'] = 800;
			$modalParams['width']  = '100%';
			$modalHtml = HTMLHelper::_('bootstrap.renderModal',
'modal-' . $this->id, $modalParams);
		}

		return $modalHtml . parent::getInput();
	}

	/**
	 * Method to get the data to be passed to the layout for rendering.
	 *
	 * @return  array
	 *
	 * @since   3.9.1
	 */
	protected function getLayoutData()
	{
		$data = parent::getLayoutData();

		$extraData = array(
			'articleid' => (integer) $this->articleid,
		);

		return array_merge($data, $extraData);
	}

	/**
	 * Return the url of the assigned article based on the current user
language
	 *
	 * @return  string  Returns the link to the article
	 *
	 * @since   3.9.1
	 */
	private function getAssignedArticleUrl()
	{
		$db = Factory::getDbo();

		// Get the info from the article
		$query = $db->getQuery(true)
			->select($db->quoteName(array('id', 'catid',
'language')))
			->from($db->quoteName('#__content'))
			->where($db->quoteName('id') . ' = ' . (int)
$this->articleid);
		$db->setQuery($query);

		try
		{
			$article = $db->loadObject();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			// Something at the database layer went wrong
			return Route::_(
				'index.php?option=com_content&view=article&id='
				. $this->articleid . '&tmpl=component'
			);
		}

		if (!is_object($article))
		{
			// We have not found the article object lets show a 404 to the user
			return Route::_(
				'index.php?option=com_content&view=article&id='
				. $this->articleid . '&tmpl=component'
			);
		}

		// Register ContentHelperRoute
		JLoader::register('ContentHelperRoute', JPATH_BASE .
'/components/com_content/helpers/route.php');

		if (!Associations::isEnabled())
		{
			return Route::_(
				ContentHelperRoute::getArticleRoute(
					$article->id,
					$article->catid,
					$article->language
				) . '&tmpl=component'
			);
		}

		$associatedArticles =
Associations::getAssociations('com_content',
'#__content', 'com_content.item', $article->id);
		$currentLang        = Factory::getLanguage()->getTag();

		if (isset($associatedArticles) && $currentLang !==
$article->language && array_key_exists($currentLang,
$associatedArticles))
		{
			return Route::_(
				ContentHelperRoute::getArticleRoute(
					$associatedArticles[$currentLang]->id,
					$associatedArticles[$currentLang]->catid,
					$associatedArticles[$currentLang]->language
				) . '&tmpl=component'
			);
		}

		// Association is enabled but this article is not associated
		return Route::_(
			'index.php?option=com_content&view=article&id='
				. $article->id . '&catid=' . $article->catid
				. '&tmpl=component&lang=' . $article->language
		);
	}
}
content/contact/contact.php000064400000006370147357022230012030
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.Contact
 *
 * @copyright   (C) 2014 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

/**
 * Contact Plugin
 *
 * @since  3.2
 */
class PlgContentContact extends JPlugin
{
	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 * @since  3.3
	 */
	protected $db;

	/**
	 * Plugin that retrieves contact information for contact
	 *
	 * @param   string   $context  The context of the content being passed to
the plugin.
	 * @param   mixed    &$row     An object with a "text"
property
	 * @param   mixed    $params   Additional parameters. See {@see
PlgContentContent()}.
	 * @param   integer  $page     Optional page number. Unused. Defaults to
zero.
	 *
	 * @return  boolean	True on success.
	 */
	public function onContentPrepare($context, &$row, $params, $page = 0)
	{
		$allowed_contexts = array('com_content.category',
'com_content.article', 'com_content.featured');

		if (!in_array($context, $allowed_contexts))
		{
			return true;
		}

		// Return if we don't have valid params or don't link the
author
		if (!($params instanceof Registry) ||
!$params->get('link_author'))
		{
			return true;
		}

		// Return if an alias is used
		if ((int) $this->params->get('link_to_alias', 0) === 0
&& $row->created_by_alias != '')
		{
			return true;
		}

		// Return if we don't have a valid article id
		if (!isset($row->id) || !(int) $row->id)
		{
			return true;
		}

		$contact        = $this->getContactData($row->created_by);
		$row->contactid = $contact->contactid;
		$row->webpage   = $contact->webpage;
		$row->email     = $contact->email_to;
		$url            = $this->params->get('url',
'url');

		if ($row->contactid && $url === 'url')
		{
			JLoader::register('ContactHelperRoute', JPATH_SITE .
'/components/com_contact/helpers/route.php');
			$row->contact_link =
JRoute::_(ContactHelperRoute::getContactRoute($contact->contactid .
':' . $contact->alias, $contact->catid));
		}
		elseif ($row->webpage && $url === 'webpage')
		{
			$row->contact_link = $row->webpage;
		}
		elseif ($row->email && $url === 'email')
		{
			$row->contact_link = 'mailto:' . $row->email;
		}
		else
		{
			$row->contact_link = '';
		}

		return true;
	}

	/**
	 * Retrieve Contact
	 *
	 * @param   int  $userId  Id of the user who created the article
	 *
	 * @return  mixed|null|integer
	 */
	protected function getContactData($userId)
	{
		static $contacts = array();

		if (isset($contacts[$userId]))
		{
			return $contacts[$userId];
		}

		$query = $this->db->getQuery(true);

		$query->select('MAX(contact.id) AS contactid, contact.alias,
contact.catid, contact.webpage, contact.email_to');
		$query->from($this->db->quoteName('#__contact_details',
'contact'));
		$query->where('contact.published = 1');
		$query->where('contact.user_id = ' . (int) $userId);

		if (JLanguageMultilang::isEnabled() === true)
		{
			$query->where('(contact.language in '
				. '(' .
$this->db->quote(JFactory::getLanguage()->getTag()) .
',' . $this->db->quote('*') . ') '
				. ' OR contact.language IS NULL)');
		}

		$this->db->setQuery($query);

		$contacts[$userId] = $this->db->loadObject();

		return $contacts[$userId];
	}
}
content/contact/contact.xml000064400000003142147357022230012033
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin"
group="content" method="upgrade">
	<name>plg_content_contact</name>
	<author>Joomla! Project</author>
	<creationDate>January 2014</creationDate>
	<copyright>(C) 2014 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.2.2</version>
	<description>PLG_CONTENT_CONTACT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contact">contact.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_contact.ini</language>
		<language
tag="en-GB">en-GB.plg_content_contact.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="url"
					type="list"
					label="PLG_CONTENT_CONTACT_PARAM_URL_LABEL"
					description="PLG_CONTENT_CONTACT_PARAM_URL_DESCRIPTION"
					default="url"
					>
					<option
value="url">PLG_CONTENT_CONTACT_PARAM_URL_URL</option>
					<option
value="webpage">PLG_CONTENT_CONTACT_PARAM_URL_WEBPAGE</option>
					<option
value="email">PLG_CONTENT_CONTACT_PARAM_URL_EMAIL</option>
				</field>

				<field
					name="link_to_alias"
					type="radio"
					label="PLG_CONTENT_CONTACT_PARAM_ALIAS_LABEL"
					description="PLG_CONTENT_CONTACT_PARAM_ALIAS_DESCRIPTION"
					default="0"
					class="btn-group btn-group-yesno"
					filter="integer"
					>
					<option value="0">JNO</option>
					<option value="1">JYES</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
content/emailcloak/emailcloak.php000064400000042375147357022230013151
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.emailcloak
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\String\StringHelper;

/**
 * Email cloack plugin class.
 *
 * @since  1.5
 */
class PlgContentEmailcloak extends JPlugin
{
	/**
	 * Plugin that cloaks all emails in content from spambots via Javascript.
	 *
	 * @param   string   $context  The context of the content being passed to
the plugin.
	 * @param   mixed    &$row     An object with a "text"
property or the string to be cloaked.
	 * @param   mixed    &$params  Additional parameters. See {@see
PlgContentEmailcloak()}.
	 * @param   integer  $page     Optional page number. Unused. Defaults to
zero.
	 *
	 * @return  boolean	True on success.
	 */
	public function onContentPrepare($context, &$row, &$params, $page
= 0)
	{
		// Don't run this plugin when the content is being indexed
		if ($context === 'com_finder.indexer')
		{
			return true;
		}

		if (is_object($row))
		{
			return $this->_cloak($row->text, $params);
		}

		return $this->_cloak($row, $params);
	}

	/**
	 * Generate a search pattern based on link and text.
	 *
	 * @param   string  $link  The target of an email link.
	 * @param   string  $text  The text enclosed by the link.
	 *
	 * @return  string	A regular expression that matches a link containing the
parameters.
	 */
	protected function _getPattern ($link, $text)
	{
		$pattern = '~(?:<a ([^>]*)href\s*=\s*"mailto:' .
$link . '"([^>]*))>' . $text .
'</a>~i';

		return $pattern;
	}

	/**
	 * Adds an attributes to the js cloaked email.
	 *
	 * @param   string  $jsEmail  Js cloaked email.
	 * @param   string  $before   Attributes before email.
	 * @param   string  $after    Attributes after email.
	 *
	 * @return string Js cloaked email with attributes.
	 */
	protected function _addAttributesToEmail($jsEmail, $before, $after)
	{
		if ($before !== '')
		{
			$before = str_replace("'", "\'", $before);
			$jsEmail = str_replace(".innerHTML += '<a '",
".innerHTML += '<a {$before}'", $jsEmail);
		}

		if ($after !== '')
		{
			$after = str_replace("'", "\'", $after);
			$jsEmail = str_replace("'\'>'",
"'\'{$after}>'", $jsEmail);
		}

		return $jsEmail;
	}

	/**
	 * Cloak all emails in text from spambots via Javascript.
	 *
	 * @param   string  &$text    The string to be cloaked.
	 * @param   mixed   &$params  Additional parameters. Parameter
"mode" (integer, default 1)
	 *                             replaces addresses with "mailto:"
links if nonzero.
	 *
	 * @return  boolean  True on success.
	 */
	protected function _cloak(&$text, &$params)
	{
		/*
		 * Check for presence of {emailcloak=off} which is explicits disables
this
		 * bot for the item.
		 */
		if (StringHelper::strpos($text, '{emailcloak=off}') !== false)
		{
			$text = StringHelper::str_ireplace('{emailcloak=off}',
'', $text);

			return true;
		}

		// Simple performance check to determine whether bot should process
further.
		if (StringHelper::strpos($text, '@') === false)
		{
			return true;
		}

		$mode = $this->params->def('mode', 1);

		// Example: any@example.org
		$searchEmail =
'([\w\.\'\-\+]+\@(?:[a-z0-9\.\-]+\.)+(?:[a-zA-Z0-9\-]{2,24}))';

		// Example: any@example.org?subject=anyText
		$searchEmailLink = $searchEmail .
'([?&][\x20-\x7f][^"<>]+)';

		// Any Text
		$searchText =
'((?:[\x20-\x7f]|[\xA1-\xFF]|[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF4][\x80-\xBF]{3})[^<>]+)';

		// Any Image link
		$searchImage = '(<img[^>]+>)';

		// Any Text with <span or <strong
		$searchTextSpan =
'(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)'
. $searchText .
'(</span>|</strong>|</span></strong>)';

		// Any address with <span or <strong
		$searchEmailSpan =
'(<span[^>]+>|<span>|<strong>|<strong><span[^>]+>|<strong><span>)'
. $searchEmail .
'(</span>|</strong>|</span></strong>)';

		/*
		 * Search and fix derivatives of link code <a
href="http://mce_host/ourdirectory/email@example.org"
		 * >email@example.org</a>. This happens when inserting an email
in TinyMCE, cancelling its suggestion to add
		 * the mailto: prefix...
		 */
		$pattern = $this->_getPattern($searchEmail, $searchEmail);
		$pattern = str_replace('"mailto:',
'"http://mce_host([\x20-\x7f][^<>]+/)', $pattern);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[3][0];
			$mailText = $regs[5][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[4][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search and fix derivatives of link code <a
href="http://mce_host/ourdirectory/email@example.org"
		 * >anytext</a>. This happens when inserting an email in
TinyMCE, cancelling its suggestion to add
		 * the mailto: prefix...
		 */
		$pattern = $this->_getPattern($searchEmail, $searchText);
		$pattern = str_replace('"mailto:',
'"http://mce_host([\x20-\x7f][^<>]+/)', $pattern);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[3][0];
			$mailText = $regs[5][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[4][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@example.org"
		 * >email@example.org</a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchEmail);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[3][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@amail.com"
		 * ><anyspan >email@amail.com</anyspan></a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchEmailSpan);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@amail.com">
		 * <anyspan >anytext</anyspan></a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchTextSpan);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0] . addslashes($regs[5][0]) . $regs[6][0];

			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@example.org">
		 * anytext</a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchText);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = addslashes($regs[4][0]);

			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[3][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@example.org">
		 * <img anything></a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchImage);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0];

			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@example.org">
		 * <img anything>email@example.org</a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchImage .
$searchEmail);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0] . $regs[5][0];

			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@example.org">
		 * <img anything>any text</a>
		 */
		$pattern = $this->_getPattern($searchEmail, $searchImage .
$searchText);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0];
			$mailText = $regs[4][0] . addslashes($regs[5][0]);

			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[3][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@example.org?
		 * subject=Text">email@example.org</a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchEmail);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0] . $regs[3][0];
			$mailText = $regs[5][0];

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[4][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@example.org?
		 * subject=Text">anytext</a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchText);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0] . $regs[3][0];
			$mailText = addslashes($regs[5][0]);

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement = $this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[4][0]);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@amail.com?subject= Text"
		 * ><anyspan >email@amail.com</anyspan></a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchEmailSpan);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0] . $regs[3][0];
			$mailText = $regs[5][0] . $regs[6][0] . $regs[7][0];

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code <a
href="mailto:email@amail.com?subject= Text">
		 * <anyspan >anytext</anyspan></a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchTextSpan);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[2][0] . $regs[3][0];
			$mailText = $regs[5][0] . addslashes($regs[6][0]) . $regs[7][0];

			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code
		 * <a href="mailto:email@amail.com?subject=Text"><img
anything></a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchImage);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[1][0] . $regs[2][0] . $regs[3][0];
			$mailText = $regs[5][0];

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code
		 * <a href="mailto:email@amail.com?subject=Text"><img
anything>email@amail.com</a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchImage .
$searchEmail);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[1][0] . $regs[2][0] . $regs[3][0];
			$mailText = $regs[4][0] . $regs[5][0] . $regs[6][0];

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for derivatives of link code
		 * <a href="mailto:email@amail.com?subject=Text"><img
anything>any text</a>
		 */
		$pattern = $this->_getPattern($searchEmailLink, $searchImage .
$searchText);

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[1][0] . $regs[2][0] . $regs[3][0];
			$mailText = $regs[4][0] . $regs[5][0] . addslashes($regs[6][0]);

			// Needed for handling of Body parameter
			$mail = str_replace('&amp;', '&', $mail);

			// Check to see if mail text is different from mail addy
			$replacement = JHtml::_('email.cloak', $mail, $mode,
$mailText, 0);

			// Ensure that attributes is not stripped out by email cloaking
			$replacement =
html_entity_decode($this->_addAttributesToEmail($replacement,
$regs[1][0], $regs[4][0]));

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[0][1],
strlen($regs[0][0]));
		}

		/*
		 * Search for plain text email addresses, such as email@example.org but
not within HTML tags:
		 * <img src="..." title="email@example.org"> or
<input type="text"
placeholder="email@example.org">
		 * The '<[^<]*>(*SKIP)(*F)|' trick is used to exclude
this kind of occurrences
		 */
		$pattern = '~<[^<]*>(*SKIP)(*F)|' . $searchEmail .
'~i';

		while (preg_match($pattern, $text, $regs, PREG_OFFSET_CAPTURE))
		{
			$mail = $regs[1][0];
			$replacement = JHtml::_('email.cloak', $mail, $mode);

			// Replace the found address with the js cloaked email
			$text = substr_replace($text, $replacement, $regs[1][1], strlen($mail));
		}

		return true;
	}
}
content/emailcloak/emailcloak.xml000064400000002325147357022230013151
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="content" method="upgrade">
	<name>plg_content_emailcloak</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTENT_EMAILCLOAK_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="emailcloak">emailcloak.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_emailcloak.ini</language>
		<language
tag="en-GB">en-GB.plg_content_emailcloak.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="mode"
					type="list"
					label="PLG_CONTENT_EMAILCLOAK_MODE_LABEL"
					description="PLG_CONTENT_EMAILCLOAK_MODE_DESC"
					default="1"
					filter="integer"
					>
					<option
value="0">PLG_CONTENT_EMAILCLOAK_NONLINKABLE</option>
					<option
value="1">PLG_CONTENT_EMAILCLOAK_LINKABLE</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
content/fields/fields.php000064400000010140147357022240011445
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.Fields
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die();

/**
 * Plug-in to show a custom field in eg an article
 * This uses the {fields ID} syntax
 *
 * @since  3.7.0
 */
class PlgContentFields extends JPlugin
{
	/**
	 * Plugin that shows a custom field
	 *
	 * @param   string  $context  The context of the content being passed to
the plugin.
	 * @param   object  &$item    The item object.  Note $article->text
is also available
	 * @param   object  &$params  The article params
	 * @param   int     $page     The 'page' number
	 *
	 * @return void
	 *
	 * @since  3.7.0
	 */
	public function onContentPrepare($context, &$item, &$params, $page
= 0)
	{
		// If the item has a context, overwrite the existing one
		if ($context == 'com_finder.indexer' &&
!empty($item->context))
		{
			$context = $item->context;
		}
		elseif ($context == 'com_finder.indexer')
		{
			// Don't run this plugin when the content is being indexed and we
have no real context
			return;
		}

		// Don't run if there is no text property (in case of bad calls) or
it is empty
		if (empty($item->text))
		{
			return;
		}

		// Simple performance check to determine whether bot should process
further
		if (strpos($item->text, 'field') === false)
		{
			return;
		}

		// Register FieldsHelper
		JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR .
'/components/com_fields/helpers/fields.php');

		// Prepare the text
		if (isset($item->text))
		{
			$item->text = $this->prepare($item->text, $context, $item);
		}

		// Prepare the intro text
		if (isset($item->introtext))
		{
			$item->introtext = $this->prepare($item->introtext, $context,
$item);
		}
	}

	/**
	 * Prepares the given string by parsing {field} and {fieldgroup} groups
and replacing them.
	 *
	 * @param   string  $string   The text to prepare
	 * @param   string  $context  The context of the content
	 * @param   object  $item     The item object
	 *
	 * @return string
	 *
	 * @since  3.8.1
	 */
	private function prepare($string, $context, $item)
	{
		// Search for {field ID} or {fieldgroup ID} tags and put the results into
$matches.
		$regex = '/{(field|fieldgroup)\s+(.*?)}/i';
		preg_match_all($regex, $string, $matches, PREG_SET_ORDER);

		if (!$matches)
		{
			return $string;
		}

		$parts = FieldsHelper::extract($context);

		if (count($parts) < 2)
		{
			return $string;
		}

		$context    = $parts[0] . '.' . $parts[1];
		$fields     = FieldsHelper::getFields($context, $item, true);
		$fieldsById = array();
		$groups     = array();

		// Rearranging fields in arrays for easier lookup later.
		foreach ($fields as $field)
		{
			$fieldsById[$field->id]     = $field;
			$groups[$field->group_id][] = $field;
		}

		foreach ($matches as $i => $match)
		{
			// $match[0] is the full pattern match, $match[1] is the type (field or
fieldgroup) and $match[2] the ID and optional the layout
			$explode = explode(',', $match[2]);
			$id      = (int) $explode[0];
			$output  = '';

			if ($match[1] == 'field' && $id)
			{
				if (isset($fieldsById[$id]))
				{
					$layout = !empty($explode[1]) ? trim($explode[1]) :
$fieldsById[$id]->params->get('layout',
'render');
					$output = FieldsHelper::render(
						$context,
						'field.' . $layout,
						array(
							'item'    => $item,
							'context' => $context,
							'field'   => $fieldsById[$id]
						)
					);
				}
			}
			else
			{
				if ($match[2] === '*')
				{
					$match[0]     = str_replace('*', '\*', $match[0]);
					$renderFields = $fields;
				}
				else
				{
					$renderFields = isset($groups[$id]) ? $groups[$id] : '';
				}

				if ($renderFields)
				{
					$layout = !empty($explode[1]) ? trim($explode[1]) :
'render';
					$output = FieldsHelper::render(
						$context,
						'fields.' . $layout,
						array(
							'item'    => $item,
							'context' => $context,
							'fields'  => $renderFields
						)
					);
				}
			}

			$string = preg_replace("|$match[0]|", addcslashes($output,
'\\$'), $string, 1);
		}

		return $string;
	}
}
content/fields/fields.xml000064400000001561147357022240011465
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7.0" type="plugin"
group="content" method="upgrade">
	<name>plg_content_fields</name>
	<author>Joomla! Project</author>
	<creationDate>February 2017</creationDate>
	<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_CONTENT_FIELDS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="fields">fields.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_fields.ini</language>
		<language
tag="en-GB">en-GB.plg_content_fields.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
			</fieldset>
		</fields>
	</config>
</extension>
content/finder/finder.php000064400000007715147357022240011465
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.finder
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Smart Search Content Plugin
 *
 * @since  2.5
 */
class PlgContentFinder extends JPlugin
{
	/**
	 * Smart Search after save content method.
	 * Content is passed by reference, but after the save, so no changes will
be saved.
	 * Method is called right after the content is saved.
	 *
	 * @param   string  $context  The context of the content passed to the
plugin (added in 1.6)
	 * @param   object  $article  A JTableContent object
	 * @param   bool    $isNew    If the content has just been created
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onContentAfterSave($context, $article, $isNew)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderAfterSave event.
		$dispatcher->trigger('onFinderAfterSave', array($context,
$article, $isNew));
	}

	/**
	 * Smart Search before save content method.
	 * Content is passed by reference. Method is called before the content is
saved.
	 *
	 * @param   string  $context  The context of the content passed to the
plugin (added in 1.6).
	 * @param   object  $article  A JTableContent object.
	 * @param   bool    $isNew    If the content is just about to be created.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onContentBeforeSave($context, $article, $isNew)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderBeforeSave event.
		$dispatcher->trigger('onFinderBeforeSave', array($context,
$article, $isNew));
	}

	/**
	 * Smart Search after delete content method.
	 * Content is passed by reference, but after the deletion.
	 *
	 * @param   string  $context  The context of the content passed to the
plugin (added in 1.6).
	 * @param   object  $article  A JTableContent object.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onContentAfterDelete($context, $article)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderAfterDelete event.
		$dispatcher->trigger('onFinderAfterDelete', array($context,
$article));
	}

	/**
	 * Smart Search content state change method.
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the
plugin.
	 * @param   array    $pks      A list of primary key ids of the content
that has changed state.
	 * @param   integer  $value    The value of the state that the content has
been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onContentChangeState($context, $pks, $value)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderChangeState event.
		$dispatcher->trigger('onFinderChangeState', array($context,
$pks, $value));
	}

	/**
	 * Smart Search change category state content method.
	 * Method is called when the state of the category to which the
	 * content item belongs is changed.
	 *
	 * @param   string   $extension  The extension whose category has been
updated.
	 * @param   array    $pks        A list of primary key ids of the content
that has changed state.
	 * @param   integer  $value      The value of the state that the content
has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onCategoryChangeState($extension, $pks, $value)
	{
		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('finder');

		// Trigger the onFinderCategoryChangeState event.
		$dispatcher->trigger('onFinderCategoryChangeState',
array($extension, $pks, $value));
	}
}
content/finder/finder.xml000064400000001506147357022240011466
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="content" method="upgrade">
	<name>plg_content_finder</name>
	<author>Joomla! Project</author>
	<creationDate>December 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTENT_FINDER_XML_DESCRIPTION</description>

	<files>
		<filename plugin="finder">finder.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_finder.ini</language>
		<language
tag="en-GB">en-GB.plg_content_finder.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
		</fields>
	</config>
</extension>
content/joomla/joomla.php000064400000021365147357022240011506
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.joomla
 *
 * @copyright   (C) 2010 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Example Content Plugin
 *
 * @since  1.6
 */
class PlgContentJoomla extends JPlugin
{
	/**
	 * Example after save content method
	 * Article is passed by reference, but after the save, so no changes will
be saved.
	 * Method is called right after the content is saved
	 *
	 * @param   string   $context  The context of the content passed to the
plugin (added in 1.6)
	 * @param   object   $article  A JTableContent object
	 * @param   boolean  $isNew    If the content is just about to be created
	 *
	 * @return  boolean   true if function not enabled, is in frontend or is
new. Else true or
	 *                    false depending on success of save function.
	 *
	 * @since   1.6
	 */
	public function onContentAfterSave($context, $article, $isNew)
	{
		// Check we are handling the frontend edit form.
		if ($context !== 'com_content.form')
		{
			return true;
		}

		// Check if this function is enabled.
		if (!$this->params->def('email_new_fe', 1))
		{
			return true;
		}

		// Check this is a new article.
		if (!$isNew)
		{
			return true;
		}

		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName('id'))
			->from($db->quoteName('#__users'))
			->where($db->quoteName('sendEmail') . ' = 1')
			->where($db->quoteName('block') . ' = 0');
		$db->setQuery($query);
		$users = (array) $db->loadColumn();

		if (empty($users))
		{
			return true;
		}

		$user = JFactory::getUser();

		// Messaging for new items
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_messages/models', 'MessagesModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_messages/tables');

		$default_language =
JComponentHelper::getParams('com_languages')->get('administrator');
		$debug = JFactory::getConfig()->get('debug_lang');
		$result = true;

		foreach ($users as $user_id)
		{
			if ($user_id != $user->id)
			{
				// Load language for messaging
				$receiver = JUser::getInstance($user_id);
				$lang =
JLanguage::getInstance($receiver->getParam('admin_language',
$default_language), $debug);
				$lang->load('com_content');
				$message = array(
					'user_id_to' => $user_id,
					'subject' =>
$lang->_('COM_CONTENT_NEW_ARTICLE'),
					'message' =>
sprintf($lang->_('COM_CONTENT_ON_NEW_CONTENT'),
$user->get('name'), $article->title)
				);
				$model_message = JModelLegacy::getInstance('Message',
'MessagesModel');
				$result = $model_message->save($message);
			}
		}

		return $result;
	}

	/**
	 * Don't allow categories to be deleted if they contain items or
subcategories with items
	 *
	 * @param   string  $context  The context for the content passed to the
plugin.
	 * @param   object  $data     The data relating to the content that was
deleted.
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onContentBeforeDelete($context, $data)
	{
		// Skip plugin if we are deleting something other than categories
		if ($context !== 'com_categories.category')
		{
			return true;
		}

		// Check if this function is enabled.
		if (!$this->params->def('check_categories', 1))
		{
			return true;
		}

		$extension =
JFactory::getApplication()->input->getString('extension');

		// Default to true if not a core extension
		$result = true;

		$tableInfo = array(
			'com_banners' => array('table_name' =>
'#__banners'),
			'com_contact' => array('table_name' =>
'#__contact_details'),
			'com_content' => array('table_name' =>
'#__content'),
			'com_newsfeeds' => array('table_name' =>
'#__newsfeeds'),
			'com_weblinks' => array('table_name' =>
'#__weblinks')
		);

		// Now check to see if this is a known core extension
		if (isset($tableInfo[$extension]))
		{
			// Get table name for known core extensions
			$table = $tableInfo[$extension]['table_name'];

			// See if this category has any content items
			$count = $this->_countItemsInCategory($table,
$data->get('id'));

			// Return false if db error
			if ($count === false)
			{
				$result = false;
			}
			else
			{
				// Show error if items are found in the category
				if ($count > 0)
				{
					$msg = JText::sprintf('COM_CATEGORIES_DELETE_NOT_ALLOWED',
$data->get('title'))
						. JText::plural('COM_CATEGORIES_N_ITEMS_ASSIGNED', $count);
					JError::raiseWarning(403, $msg);
					$result = false;
				}

				// Check for items in any child categories (if it is a leaf, there are
no child categories)
				if (!$data->isLeaf())
				{
					$count = $this->_countItemsInChildren($table,
$data->get('id'), $data);

					if ($count === false)
					{
						$result = false;
					}
					elseif ($count > 0)
					{
						$msg = JText::sprintf('COM_CATEGORIES_DELETE_NOT_ALLOWED',
$data->get('title'))
							. JText::plural('COM_CATEGORIES_HAS_SUBCATEGORY_ITEMS',
$count);
						JError::raiseWarning(403, $msg);
						$result = false;
					}
				}
			}

			return $result;
		}
	}

	/**
	 * Get count of items in a category
	 *
	 * @param   string   $table  table name of component table (column is
catid)
	 * @param   integer  $catid  id of the category to check
	 *
	 * @return  mixed  count of items found or false if db error
	 *
	 * @since   1.6
	 */
	private function _countItemsInCategory($table, $catid)
	{
		$db = JFactory::getDbo();
		$query = $db->getQuery(true);

		// Count the items in this category
		$query->select('COUNT(id)')
			->from($table)
			->where('catid = ' . $catid);
		$db->setQuery($query);

		try
		{
			$count = $db->loadResult();
		}
		catch (RuntimeException $e)
		{
			JError::raiseWarning(500, $e->getMessage());

			return false;
		}

		return $count;
	}

	/**
	 * Get count of items in a category's child categories
	 *
	 * @param   string   $table  table name of component table (column is
catid)
	 * @param   integer  $catid  id of the category to check
	 * @param   object   $data   The data relating to the content that was
deleted.
	 *
	 * @return  mixed  count of items found or false if db error
	 *
	 * @since   1.6
	 */
	private function _countItemsInChildren($table, $catid, $data)
	{
		$db = JFactory::getDbo();

		// Create subquery for list of child categories
		$childCategoryTree = $data->getTree();

		// First element in tree is the current category, so we can skip that one
		unset($childCategoryTree[0]);
		$childCategoryIds = array();

		foreach ($childCategoryTree as $node)
		{
			$childCategoryIds[] = $node->id;
		}

		// Make sure we only do the query if we have some categories to look in
		if (count($childCategoryIds))
		{
			// Count the items in this category
			$query = $db->getQuery(true)
				->select('COUNT(id)')
				->from($table)
				->where('catid IN (' . implode(',',
$childCategoryIds) . ')');
			$db->setQuery($query);

			try
			{
				$count = $db->loadResult();
			}
			catch (RuntimeException $e)
			{
				JError::raiseWarning(500, $e->getMessage());

				return false;
			}

			return $count;
		}
		else
			// If we didn't have any categories to check, return 0
		{
			return 0;
		}
	}

	/**
	 * Change the state in core_content if the state in a table is changed
	 *
	 * @param   string   $context  The context for the content passed to the
plugin.
	 * @param   array    $pks      A list of primary key ids of the content
that has changed state.
	 * @param   integer  $value    The value of the state that the content has
been changed to.
	 *
	 * @return  boolean
	 *
	 * @since   3.1
	 */
	public function onContentChangeState($context, $pks, $value)
	{
		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select($db->quoteName('core_content_id'))
			->from($db->quoteName('#__ucm_content'))
			->where($db->quoteName('core_type_alias') . ' =
' . $db->quote($context))
			->where($db->quoteName('core_content_item_id') . '
IN (' . $pksImploded = implode(',', $pks) . ')');
		$db->setQuery($query);
		$ccIds = $db->loadColumn();

		$cctable = new JTableCorecontent($db);
		$cctable->publish($ccIds, $value);

		return true;
	}

	/**
	* The save event.
	*
	* @param   string   $context  The context
	* @param   object   $table    The item
	* @param   boolean  $isNew    Is new item
	*
	* @return  void
	*
	* @since   3.9.12
	*/
	public function onContentBeforeSave($context, $table, $isNew)
	{
		// Check we are handling the frontend edit form.
		if ($context !== 'com_menus.item')
		{
			return true;
		}

		// Special case for Create article menu item
		if ($table->link !==
'index.php?option=com_content&view=form&layout=edit')
		{
			return true;
		}

		// Display error if catid is not set when enable_category is enabled
		$params = json_decode($table->params, true);

		if ($params['enable_category'] == 1 &&
empty($params['catid']))
		{
			$table->setError(JText::_('COM_CONTENT_CREATE_ARTICLE_ERROR'));

			return false;
		}
	}
}
content/joomla/joomla.xml000064400000003056147357022240011514
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="content" method="upgrade">
	<name>plg_content_joomla</name>
	<author>Joomla! Project</author>
	<creationDate>November 2010</creationDate>
	<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTENT_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_joomla.ini</language>
		<language
tag="en-GB">en-GB.plg_content_joomla.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="check_categories"
					type="radio"
					label="PLG_CONTENT_JOOMLA_FIELD_CHECK_CATEGORIES_LABEL"
					description="PLG_CONTENT_JOOMLA_FIELD_CHECK_CATEGORIES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field 
					name="email_new_fe"
					type="radio"
					label="PLG_CONTENT_JOOMLA_FIELD_EMAIL_NEW_FE_LABEL"
					description="PLG_CONTENT_JOOMLA_FIELD_EMAIL_NEW_FE_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>

</extension>
content/loadmodule/loadmodule.php000064400000015306147357022240013214
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.loadmodule
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Plugin to enable loading modules into content (e.g. articles)
 * This uses the {loadmodule} syntax
 *
 * @since  1.5
 */
class PlgContentLoadmodule extends JPlugin
{
	protected static $modules = array();

	protected static $mods = array();

	/**
	 * Plugin that loads module positions within content
	 *
	 * @param   string   $context   The context of the content being passed to
the plugin.
	 * @param   object   &$article  The article object.  Note
$article->text is also available
	 * @param   mixed    &$params   The article params
	 * @param   integer  $page      The 'page' number
	 *
	 * @return  mixed   true if there is an error. Void otherwise.
	 *
	 * @since   1.6
	 */
	public function onContentPrepare($context, &$article, &$params,
$page = 0)
	{
		// Don't run this plugin when the content is being indexed
		if ($context === 'com_finder.indexer')
		{
			return true;
		}

		// Simple performance check to determine whether bot should process
further
		if (strpos($article->text, 'loadposition') === false
&& strpos($article->text, 'loadmodule') === false)
		{
			return true;
		}

		// Expression to search for (positions)
		$regex = '/{loadposition\s(.*?)}/i';
		$style = $this->params->def('style', 'none');

		// Expression to search for(modules)
		$regexmod = '/{loadmodule\s(.*?)}/i';
		$stylemod = $this->params->def('style',
'none');

		// Expression to search for(id)
		$regexmodid = '/{loadmoduleid\s([1-9][0-9]*)}/i';

		// Find all instances of plugin and put in $matches for loadposition
		// $matches[0] is full pattern match, $matches[1] is the position
		preg_match_all($regex, $article->text, $matches, PREG_SET_ORDER);

		// No matches, skip this
		if ($matches)
		{
			foreach ($matches as $match)
			{
				$matcheslist = explode(',', $match[1]);

				// We may not have a module style so fall back to the plugin default.
				if (!array_key_exists(1, $matcheslist))
				{
					$matcheslist[1] = $style;
				}

				$position = trim($matcheslist[0]);
				$style    = trim($matcheslist[1]);

				$output = $this->_load($position, $style);

				// We should replace only first occurrence in order to allow positions
with the same name to regenerate their content:
				if (($start = strpos($article->text, $match[0])) !== false)
				{
					$article->text = substr_replace($article->text, $output, $start,
strlen($match[0]));
				}

				$style = $this->params->def('style', 'none');
			}
		}

		// Find all instances of plugin and put in $matchesmod for loadmodule
		preg_match_all($regexmod, $article->text, $matchesmod,
PREG_SET_ORDER);

		// If no matches, skip this
		if ($matchesmod)
		{
			foreach ($matchesmod as $matchmod)
			{
				$matchesmodlist = explode(',', $matchmod[1]);

				// We may not have a specific module so set to null
				if (!array_key_exists(1, $matchesmodlist))
				{
					$matchesmodlist[1] = null;
				}

				// We may not have a module style so fall back to the plugin default.
				if (!array_key_exists(2, $matchesmodlist))
				{
					$matchesmodlist[2] = $stylemod;
				}

				$module = trim($matchesmodlist[0]);
				$name   = htmlspecialchars_decode(trim($matchesmodlist[1]));
				$stylemod  = trim($matchesmodlist[2]);

				// $match[0] is full pattern match, $match[1] is the module,$match[2]
is the title
				$output = $this->_loadmod($module, $name, $stylemod);

				// We should replace only first occurrence in order to allow positions
with the same name to regenerate their content:
				if (($start = strpos($article->text, $matchmod[0])) !== false)
				{
					$article->text = substr_replace($article->text, $output, $start,
strlen($matchmod[0]));
				}

				$stylemod = $this->params->def('style',
'none');
			}
		}

		// Find all instances of plugin and put in $matchesmodid for loadmoduleid
		preg_match_all($regexmodid, $article->text, $matchesmodid,
PREG_SET_ORDER);

		// If no matches, skip this
		if ($matchesmodid)
		{
			foreach ($matchesmodid as $match)
			{
				$id     = trim($match[1]);
				$output = $this->_loadid($id);

				// We should replace only first occurrence in order to allow positions
with the same name to regenerate their content:
				if (($start = strpos($article->text, $match[0])) !== false)
				{
					$article->text = substr_replace($article->text, $output, $start,
strlen($match[0]));
				}

				$style = $this->params->def('style', 'none');
			}
		}
	}

	/**
	 * Loads and renders the module
	 *
	 * @param   string  $position  The position assigned to the module
	 * @param   string  $style     The style assigned to the module
	 *
	 * @return  mixed
	 *
	 * @since   1.6
	 */
	protected function _load($position, $style = 'none')
	{
		self::$modules[$position] = '';
		$document = JFactory::getDocument();
		$renderer = $document->loadRenderer('module');
		$modules  = JModuleHelper::getModules($position);
		$params   = array('style' => $style);
		ob_start();

		foreach ($modules as $module)
		{
			echo $renderer->render($module, $params);
		}

		self::$modules[$position] = ob_get_clean();

		return self::$modules[$position];
	}

	/**
	 * This is always going to get the first instance of the module type
unless
	 * there is a title.
	 *
	 * @param   string  $module  The module title
	 * @param   string  $title   The title of the module
	 * @param   string  $style   The style of the module
	 *
	 * @return  mixed
	 *
	 * @since   1.6
	 */
	protected function _loadmod($module, $title, $style = 'none')
	{
		self::$mods[$module] = '';
		$document = JFactory::getDocument();
		$renderer = $document->loadRenderer('module');
		$mod      = JModuleHelper::getModule($module, $title);

		// If the module without the mod_ isn't found, try it with mod_.
		// This allows people to enter it either way in the content
		if (!isset($mod))
		{
			$name = 'mod_' . $module;
			$mod  = JModuleHelper::getModule($name, $title);
		}

		$params = array('style' => $style);
		ob_start();

		if ($mod->id)
		{
			echo $renderer->render($mod, $params);
		}

		self::$mods[$module] = ob_get_clean();

		return self::$mods[$module];
	}

	/**
	 * Loads and renders the module
	 *
	 * @param   string  $id  The id of the module
	 *
	 * @return  mixed
	 *
	 * @since   3.9.0
	 */
	protected function _loadid($id)
	{
		self::$modules[$id] = '';
		$document = JFactory::getDocument();
		$renderer = $document->loadRenderer('module');
		$modules  = JModuleHelper::getModuleById($id);
		$params   = array('style' => 'none');
		ob_start();

		if ($modules->id > 0)
		{
			echo $renderer->render($modules, $params);
		}

		self::$modules[$id] = ob_get_clean();

		return self::$modules[$id];
	}
}
content/loadmodule/loadmodule.xml000064400000002631147357022240013222
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="content" method="upgrade">
	<name>plg_content_loadmodule</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_LOADMODULE_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="loadmodule">loadmodule.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_loadmodule.ini</language>
		<language
tag="en-GB">en-GB.plg_content_loadmodule.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="style"
					type="list"
					label="PLG_LOADMODULE_FIELD_STYLE_LABEL"
					description="PLG_LOADMODULE_FIELD_STYLE_DESC"
					default="table"
					>
					<option
value="table">PLG_LOADMODULE_FIELD_VALUE_TABLE</option>
					<option
value="horz">PLG_LOADMODULE_FIELD_VALUE_HORIZONTAL</option>
					<option
value="xhtml">PLG_LOADMODULE_FIELD_VALUE_DIVS</option>
					<option
value="rounded">PLG_LOADMODULE_FIELD_VALUE_MULTIPLEDIVS</option>
					<option
value="none">PLG_LOADMODULE_FIELD_VALUE_RAW</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
content/pagebreak/pagebreak.php000064400000022765147357022240012613
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagebreak
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\String\StringHelper;

jimport('joomla.utilities.utility');

JLoader::register('ContentHelperRoute', JPATH_SITE .
'/components/com_content/helpers/route.php');

/**
 * Page break plugin
 *
 * <b>Usage:</b>
 * <code><hr class="system-pagebreak" /></code>
 * <code><hr class="system-pagebreak" title="The
page title" /></code>
 * or
 * <code><hr class="system-pagebreak" alt="The
first page" /></code>
 * or
 * <code><hr class="system-pagebreak" title="The
page title" alt="The first page" /></code>
 * or
 * <code><hr class="system-pagebreak" alt="The
first page" title="The page title" /></code>
 *
 * @since  1.6
 */
class PlgContentPagebreak extends JPlugin
{
	/**
	 * The navigation list with all page objects if parameter
'multipage_toc' is active.
	 *
	 * @var    array
	 * @since  3.9.2
	 */
	protected $list = array();

	/**
	 * Plugin that adds a pagebreak into the text and truncates text at that
point
	 *
	 * @param   string   $context  The context of the content being passed to
the plugin.
	 * @param   object   &$row     The article object.  Note
$article->text is also available
	 * @param   mixed    &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  mixed  Always returns void or true
	 *
	 * @since   1.6
	 */
	public function onContentPrepare($context, &$row, &$params, $page
= 0)
	{
		$canProceed = $context === 'com_content.article';

		if (!$canProceed)
		{
			return;
		}

		$style = $this->params->get('style', 'pages');

		// Expression to search for.
		$regex =
'#<hr(.*)class="system-pagebreak"(.*)\/>#iU';

		$input = JFactory::getApplication()->input;

		$print = $input->getBool('print');
		$showall = $input->getBool('showall');

		if (!$this->params->get('enabled', 1))
		{
			$print = true;
		}

		if ($print)
		{
			$row->text = preg_replace($regex, '<br />',
$row->text);

			return true;
		}

		// Simple performance check to determine whether bot should process
further.
		if (StringHelper::strpos($row->text,
'class="system-pagebreak') === false)
		{
			if ($page > 0)
			{
				throw new Exception(JText::_('JERROR_PAGE_NOT_FOUND'), 404);
			}

			return true;
		}

		$view = $input->getString('view');
		$full = $input->getBool('fullview');

		if (!$page)
		{
			$page = 0;
		}

		if ($full || $view !== 'article' ||
$params->get('intro_only') ||
$params->get('popup'))
		{
			$row->text = preg_replace($regex, '', $row->text);

			return;
		}

		// Load plugin language files only when needed (ex: not needed if no
system-pagebreak class exists).
		$this->loadLanguage();

		// Find all instances of plugin and put in $matches.
		$matches = array();
		preg_match_all($regex, $row->text, $matches, PREG_SET_ORDER);

		if ($showall && $this->params->get('showall', 1))
		{
			$hasToc = $this->params->get('multipage_toc', 1);

			if ($hasToc)
			{
				// Display TOC.
				$page = 1;
				$this->_createToc($row, $matches, $page);
			}
			else
			{
				$row->toc = '';
			}

			$row->text = preg_replace($regex, '<br />',
$row->text);

			return true;
		}

		// Split the text around the plugin.
		$text = preg_split($regex, $row->text);

		if (!isset($text[$page]))
		{
			throw new Exception(JText::_('JERROR_PAGE_NOT_FOUND'), 404);
		}

		// Count the number of pages.
		$n = count($text);

		// We have found at least one plugin, therefore at least 2 pages.
		if ($n > 1)
		{
			$title  = $this->params->get('title', 1);
			$hasToc = $this->params->get('multipage_toc', 1);

			// Adds heading or title to <site> Title.
			if ($title && $page && isset($matches[$page - 1][0]))
			{
				$attrs = JUtility::parseAttributes($matches[$page - 1][0]);

				if (isset($attrs['title']))
				{
					$row->page_title = $attrs['title'];
				}
			}

			// Reset the text, we already hold it in the $text array.
			$row->text = '';

			if ($style === 'pages')
			{
				// Display TOC.
				if ($hasToc)
				{
					$this->_createToc($row, $matches, $page);
				}
				else
				{
					$row->toc = '';
				}

				// Traditional mos page navigation
				$pageNav = new JPagination($n, $page, 1);

				// Flag indicates to not add limitstart=0 to URL
				$pageNav->hideEmptyLimitstart = true;

				// Page counter.
				$row->text .= '<div
class="pagenavcounter">';
				$row->text .= $pageNav->getPagesCounter();
				$row->text .= '</div>';

				// Page text.
				$text[$page] = str_replace('<hr id="system-readmore"
/>', '', $text[$page]);
				$row->text .= $text[$page];

				// $row->text .= '<br />';
				$row->text .= '<div class="pager">';

				// Adds navigation between pages to bottom of text.
				if ($hasToc)
				{
					$this->_createNavigation($row, $page, $n);
				}

				// Page links shown at bottom of page if TOC disabled.
				if (!$hasToc)
				{
					$row->text .= $pageNav->getPagesLinks();
				}

				$row->text .= '</div>';
			}
			else
			{
				$t[] = $text[0];

				$t[] = (string) JHtml::_($style . '.start',
'article' . $row->id . '-' . $style);

				foreach ($text as $key => $subtext)
				{
					if ($key >= 1)
					{
						$match = $matches[$key - 1];
						$match = (array) JUtility::parseAttributes($match[0]);

						if (isset($match['alt']))
						{
							$title = stripslashes($match['alt']);
						}
						elseif (isset($match['title']))
						{
							$title = stripslashes($match['title']);
						}
						else
						{
							$title = JText::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM',
$key + 1);
						}

						$t[] = (string) JHtml::_($style . '.panel', $title,
'article' . $row->id . '-' . $style . $key);
					}

					$t[] = (string) $subtext;
				}

				$t[] = (string) JHtml::_($style . '.end');

				$row->text = implode(' ', $t);
			}
		}

		return true;
	}

	/**
	 * Creates a Table of Contents for the pagebreak
	 *
	 * @param   object   &$row      The article object.  Note
$article->text is also available
	 * @param   array    &$matches  Array of matches of a regex in
onContentPrepare
	 * @param   integer  &$page     The 'page' number
	 *
	 * @return  void
	 *
	 * @since  1.6
	 */
	protected function _createToc(&$row, &$matches, &$page)
	{
		$heading     = isset($row->title) ? $row->title :
JText::_('PLG_CONTENT_PAGEBREAK_NO_TITLE');
		$input       = JFactory::getApplication()->input;
		$limitstart  = $input->getUInt('limitstart', 0);
		$showall     = $input->getInt('showall', 0);
		$headingtext = '';

		if ($this->params->get('article_index', 1) == 1)
		{
			$headingtext =
JText::_('PLG_CONTENT_PAGEBREAK_ARTICLE_INDEX');

			if ($this->params->get('article_index_text'))
			{
				$headingtext =
htmlspecialchars($this->params->get('article_index_text'),
ENT_QUOTES, 'UTF-8');
			}
		}

		// TOC first Page link.
		$this->list[1]          = new stdClass;
		$this->list[1]->liClass = ($limitstart === 0 && $showall
=== 0) ? 'toclink active' : 'toclink';
		$this->list[1]->class   = $this->list[1]->liClass;
		$this->list[1]->link    =
JRoute::_(ContentHelperRoute::getArticleRoute($row->slug,
$row->catid, $row->language));
		$this->list[1]->title   = $heading;

		$i = 2;

		foreach ($matches as $bot)
		{
			if (@$bot[0])
			{
				$attrs2 = JUtility::parseAttributes($bot[0]);

				if (@$attrs2['alt'])
				{
					$title = stripslashes($attrs2['alt']);
				}
				elseif (@$attrs2['title'])
				{
					$title = stripslashes($attrs2['title']);
				}
				else
				{
					$title = JText::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM',
$i);
				}
			}
			else
			{
				$title = JText::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM',
$i);
			}

			$this->list[$i]          = new stdClass;
			$this->list[$i]->link    =
JRoute::_(ContentHelperRoute::getArticleRoute($row->slug,
$row->catid, $row->language) . '&limitstart=' . ($i -
1));
			$this->list[$i]->title   = $title;
			$this->list[$i]->liClass = ($limitstart === $i - 1) ?
'active' : '';
			$this->list[$i]->class   = ($limitstart === $i - 1) ?
'toclink active' : 'toclink';

			$i++;
		}

		if ($this->params->get('showall'))
		{
			$this->list[$i]          = new stdClass;
			$this->list[$i]->link    =
JRoute::_(ContentHelperRoute::getArticleRoute($row->slug,
$row->catid, $row->language) . '&showall=1');
			$this->list[$i]->liClass = ($showall === 1) ? 'active' :
'';
			$this->list[$i]->class   = ($showall === 1) ? 'toclink
active' : 'toclink';
			$this->list[$i]->title   =
JText::_('PLG_CONTENT_PAGEBREAK_ALL_PAGES');
		}

		$list = $this->list;
		$path = JPluginHelper::getLayoutPath('content',
'pagebreak', 'toc');
		ob_start();
		include $path;
		$row->toc = ob_get_clean();
	}

	/**
	 * Creates the navigation for the item
	 *
	 * @param   object  &$row  The article object.  Note $article->text
is also available
	 * @param   int     $page  The page number
	 * @param   int     $n     The total number of pages
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	protected function _createNavigation(&$row, $page, $n)
	{
		$links = array(
			'next' => '',
			'previous' => ''
		);

		if ($page < $n - 1)
		{
			$links['next'] =
JRoute::_(ContentHelperRoute::getArticleRoute($row->slug,
$row->catid, $row->language) . '&limitstart=' . ($page
+ 1));
		}

		if ($page > 0)
		{
			$links['previous'] =
ContentHelperRoute::getArticleRoute($row->slug, $row->catid,
$row->language);

			if ($page > 1)
			{
				$links['previous'] .= '&limitstart=' . ($page -
1);
			}

			$links['previous'] = JRoute::_($links['previous']);
		}

		$path = JPluginHelper::getLayoutPath('content',
'pagebreak', 'navigation');
		ob_start();
		include $path;
		$row->text .= ob_get_clean();
	}
}
content/pagebreak/pagebreak.xml000064400000005427147357022240012620
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="content" method="upgrade">
	<name>plg_content_pagebreak</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTENT_PAGEBREAK_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="pagebreak">pagebreak.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_pagebreak.ini</language>
		<language
tag="en-GB">en-GB.plg_content_pagebreak.sys.ini</language>
	</languages>
	<config>
		<fields name="params">

			<fieldset name="basic">
				<field
					name="title"
					type="radio"
					label="PLG_CONTENT_PAGEBREAK_SITE_TITLE_LABEL"
					description="PLG_CONTENT_PAGEBREAK_SITE_TITLE_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JSHOW</option>
					<option value="0">JHIDE</option>
				</field>

				<field
					name="article_index"
					type="radio"
					label="PLG_CONTENT_PAGEBREAK_SITE_ARTICLEINDEX_LABEL"
					description="PLG_CONTENT_PAGEBREAK_SITE_ARTICLEINDEX_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JSHOW</option>
					<option value="0">JHIDE</option>
				</field>

				<field
					name="article_index_text"
					type="text"
					label="PLG_CONTENT_PAGEBREAK_SITE_ARTICLEINDEXTEXT"
					description="PLG_CONTENT_PAGEBREAK_SITE_ARTICLEINDEXTEXT_DESC"
					showon="article_index:1"
				/>

				<field
					name="multipage_toc"
					type="radio"
					label="PLG_CONTENT_PAGEBREAK_TOC_LABEL"
					description="PLG_CONTENT_PAGEBREAK_TOC_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JSHOW</option>
					<option value="0">JHIDE</option>
				</field>

				<field
					name="showall"
					type="radio"
					label="PLG_CONTENT_PAGEBREAK_SHOW_ALL_LABEL"
					description="PLG_CONTENT_PAGEBREAK_SHOW_ALL_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JSHOW</option>
					<option value="0">JHIDE</option>
				</field>

				<field
					name="style"
					type="list"
					label="PLG_CONTENT_PAGEBREAK_STYLE_LABEL"
					description="PLG_CONTENT_PAGEBREAK_STYLE_DESC"
					default="pages"
					>
					<option
value="pages">PLG_CONTENT_PAGEBREAK_PAGES</option>
					<option
value="sliders">PLG_CONTENT_PAGEBREAK_SLIDERS</option>
					<option
value="tabs">PLG_CONTENT_PAGEBREAK_TABS</option>
				</field>
			</fieldset>

		</fields>
	</config>
</extension>
content/pagebreak/tmpl/navigation.php000064400000002663147357022240014000
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagebreak
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

$lang = JFactory::getLanguage();
?>
<ul>
	<li>
		<?php if ($links['previous']) :
		$direction = $lang->isRtl() ? 'right' : 'left';
		$title = htmlspecialchars($this->list[$page]->title, ENT_QUOTES,
'UTF-8');
		$ariaLabel = JText::_('JPREVIOUS') . ': ' . $title .
' (' .
JText::sprintf('JLIB_HTML_PAGE_CURRENT_OF_TOTAL', $page, $n) .
')';
		?>
		<a href="<?php echo $links['previous']; ?>"
title="<?php echo $title; ?>" aria-label="<?php
echo $ariaLabel; ?>" rel="prev">
			<?php echo '<span class="icon-chevron-' .
$direction . '" aria-hidden="true"></span>
' . JText::_('JPREV'); ?>
		</a>
		<?php endif; ?>
	</li>
	<li>
		<?php if ($links['next']) :
		$direction = $lang->isRtl() ? 'left' : 'right';
		$title = htmlspecialchars($this->list[$page + 2]->title,
ENT_QUOTES, 'UTF-8');
		$ariaLabel = JText::_('JNEXT') . ': ' . $title .
' (' .
JText::sprintf('JLIB_HTML_PAGE_CURRENT_OF_TOTAL', ($page + 2),
$n) . ')';
		?>
		<a href="<?php echo $links['next']; ?>"
title="<?php echo $title; ?>" aria-label="<?php
echo $ariaLabel; ?>" rel="next">
			<?php echo JText::_('JNEXT') . ' <span
class="icon-chevron-' . $direction . '"
aria-hidden="true"></span>'; ?>
		</a>
		<?php endif; ?>
	</li>
</ul>
content/pagebreak/tmpl/toc.php000064400000001366147357022240012425
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagebreak
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;
?>
<div class="pull-right article-index">

	<?php if ($headingtext) : ?>
	<h3><?php echo $headingtext; ?></h3>
	<?php endif; ?>

	<ul class="nav nav-tabs nav-stacked">
	<?php foreach ($list as $listItem) : ?>
		<?php $class = $listItem->liClass ? ' class="' .
$listItem->liClass . '"' : ''; ?>
		<li<?php echo $class; ?>>
			<a href="<?php echo $listItem->link; ?>"
class="<?php echo $listItem->class; ?>">
				<?php echo $listItem->title; ?>
			</a>
		</li>
	<?php endforeach; ?>
	</ul>
</div>
content/pagenavigation/pagenavigation.php000064400000016421147357022240014731
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagenavigation
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('ContentHelperRoute', JPATH_SITE .
'/components/com_content/helpers/route.php');

/**
 * Pagenavigation plugin class.
 *
 * @since  1.5
 */
class PlgContentPagenavigation extends JPlugin
{
	/**
	 * If in the article view and the parameter is enabled shows the page
navigation
	 *
	 * @param   string   $context  The context of the content being passed to
the plugin
	 * @param   object   &$row     The article object
	 * @param   mixed    &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  mixed  void or true
	 *
	 * @since   1.6
	 */
	public function onContentBeforeDisplay($context, &$row, &$params,
$page = 0)
	{
		$app   = JFactory::getApplication();
		$view  = $app->input->get('view');
		$print = $app->input->getBool('print');

		if ($print)
		{
			return false;
		}

		if ($context === 'com_content.article' && $view ===
'article' &&
$params->get('show_item_navigation'))
		{
			$db       = JFactory::getDbo();
			$user     = JFactory::getUser();
			$lang     = JFactory::getLanguage();
			$nullDate = $db->getNullDate();

			$date = JFactory::getDate();
			$now  = $date->toSql();

			$uid        = $row->id;
			$option     = 'com_content';
			$canPublish = $user->authorise('core.edit.state', $option .
'.article.' . $row->id);

			/**
			 * The following is needed as different menu items types utilise a
different param to control ordering.
			 * For Blogs the `orderby_sec` param is the order controlling param.
			 * For Table and List views it is the `orderby` param.
			**/
			$params_list = $params->toArray();

			if (array_key_exists('orderby_sec', $params_list))
			{
				$order_method = $params->get('orderby_sec', '');
			}
			else
			{
				$order_method = $params->get('orderby', '');
			}

			// Additional check for invalid sort ordering.
			if ($order_method === 'front')
			{
				$order_method = '';
			}

			// Get the order code
			$orderDate = $params->get('order_date');
			$queryDate = $this->getQueryDate($orderDate);

			// Determine sort order.
			switch ($order_method)
			{
				case 'date' :
					$orderby = $queryDate;
					break;
				case 'rdate' :
					$orderby = $queryDate . ' DESC ';
					break;
				case 'alpha' :
					$orderby = 'a.title';
					break;
				case 'ralpha' :
					$orderby = 'a.title DESC';
					break;
				case 'hits' :
					$orderby = 'a.hits';
					break;
				case 'rhits' :
					$orderby = 'a.hits DESC';
					break;
				case 'order' :
					$orderby = 'a.ordering';
					break;
				case 'author' :
					$orderby = 'a.created_by_alias, u.name';
					break;
				case 'rauthor' :
					$orderby = 'a.created_by_alias DESC, u.name DESC';
					break;
				case 'front' :
					$orderby = 'f.ordering';
					break;
				default :
					$orderby = 'a.ordering';
					break;
			}

			$xwhere = ' AND (a.state = 1 OR a.state = -1)'
				. ' AND (publish_up = ' . $db->quote($nullDate) . '
OR publish_up <= ' . $db->quote($now) . ')'
				. ' AND (publish_down = ' . $db->quote($nullDate) . '
OR publish_down >= ' . $db->quote($now) . ')';

			// Array of articles in same category correctly ordered.
			$query = $db->getQuery(true);

			// Sqlsrv changes
			$case_when = ' CASE WHEN ' .
$query->charLength('a.alias', '!=', '0');
			$a_id = $query->castAsChar('a.id');
			$case_when .= ' THEN ' . $query->concatenate(array($a_id,
'a.alias'), ':');
			$case_when .= ' ELSE ' . $a_id . ' END as slug';

			$case_when1 = ' CASE WHEN ' .
$query->charLength('cc.alias', '!=', '0');
			$c_id = $query->castAsChar('cc.id');
			$case_when1 .= ' THEN ' . $query->concatenate(array($c_id,
'cc.alias'), ':');
			$case_when1 .= ' ELSE ' . $c_id . ' END as catslug';
			$query->select('a.id, a.title, a.catid, a.language,' .
$case_when . ',' . $case_when1)
				->from('#__content AS a')
				->join('LEFT', '#__categories AS cc ON cc.id =
a.catid');

			if ($order_method === 'author' || $order_method ===
'rauthor')
			{
				$query->select('a.created_by, u.name');
				$query->join('LEFT', '#__users AS u ON u.id =
a.created_by');
			}

			$query->where(
					'a.catid = ' . (int) $row->catid . ' AND a.state =
' . (int) $row->state
						. ($canPublish ? '' : ' AND a.access IN (' .
implode(',', JAccess::getAuthorisedViewLevels($user->id)) .
') ') . $xwhere
				);
			$query->order($orderby);

			if ($app->isClient('site') &&
$app->getLanguageFilter())
			{
				$query->where('a.language in (' .
$db->quote($lang->getTag()) . ',' .
$db->quote('*') . ')');
			}

			$db->setQuery($query);
			$list = $db->loadObjectList('id');

			// This check needed if incorrect Itemid is given resulting in an
incorrect result.
			if (!is_array($list))
			{
				$list = array();
			}

			reset($list);

			// Location of current content item in array list.
			$location = array_search($uid, array_keys($list));
			$rows     = array_values($list);

			$row->prev = null;
			$row->next = null;

			if ($location - 1 >= 0)
			{
				// The previous content item cannot be in the array position -1.
				$row->prev = $rows[$location - 1];
			}

			if (($location + 1) < count($rows))
			{
				// The next content item cannot be in an array position greater than
the number of array postions.
				$row->next = $rows[$location + 1];
			}

			if ($row->prev)
			{
				$row->prev_label = ($this->params->get('display', 0)
== 0) ? JText::_('JPREV') : $row->prev->title;
				$row->prev =
JRoute::_(ContentHelperRoute::getArticleRoute($row->prev->slug,
$row->prev->catid, $row->prev->language));
			}
			else
			{
				$row->prev_label = '';
				$row->prev = '';
			}

			if ($row->next)
			{
				$row->next_label = ($this->params->get('display', 0)
== 0) ? JText::_('JNEXT') : $row->next->title;
				$row->next =
JRoute::_(ContentHelperRoute::getArticleRoute($row->next->slug,
$row->next->catid, $row->next->language));
			}
			else
			{
				$row->next_label = '';
				$row->next = '';
			}

			// Output.
			if ($row->prev || $row->next)
			{
				// Get the path for the layout file
				$path = JPluginHelper::getLayoutPath('content',
'pagenavigation');

				// Render the pagenav
				ob_start();
				include $path;
				$row->pagination = ob_get_clean();

				$row->paginationposition =
$this->params->get('position', 1);

				// This will default to the 1.5 and 1.6-1.7 behavior.
				$row->paginationrelative =
$this->params->get('relative', 0);
			}
		}
	}

	/**
	 * Translate an order code to a field for primary ordering.
	 *
	 * @param   string  $orderDate  The ordering code.
	 *
	 * @return  string  The SQL field(s) to order by.
	 *
	 * @since   3.3
	 */
	private static function getQueryDate($orderDate)
	{
		$db = JFactory::getDbo();

		switch ($orderDate)
		{
			// Use created if modified is not set
			case 'modified' :
				$queryDate = ' CASE WHEN a.modified = ' .
$db->quote($db->getNullDate()) . ' THEN a.created ELSE
a.modified END';
				break;

			// Use created if publish_up is not set
			case 'published' :
				$queryDate = ' CASE WHEN a.publish_up = ' .
$db->quote($db->getNullDate()) . ' THEN a.created ELSE
a.publish_up END ';
				break;

			// Use created as default
			case 'created' :
			default :
				$queryDate = ' a.created ';
				break;
		}

		return $queryDate;
	}
}
content/pagenavigation/pagenavigation.xml000064400000003742147357022240014744
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="content" method="upgrade">
	<name>plg_content_pagenavigation</name>
	<author>Joomla! Project</author>
	<creationDate>January 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_PAGENAVIGATION_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="pagenavigation">pagenavigation.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_pagenavigation.ini</language>
		<language
tag="en-GB">en-GB.plg_content_pagenavigation.sys.ini</language>
	</languages>
	<config>
		<fields name="params">

			<fieldset name="basic">
				<field
					name="position"
					type="list"
					label="PLG_PAGENAVIGATION_FIELD_POSITION_LABEL"
					description="PLG_PAGENAVIGATION_FIELD_POSITION_DESC"
					default="1"
					filter="integer"
					>
					<option
value="1">PLG_PAGENAVIGATION_FIELD_VALUE_BELOW</option>
					<option
value="0">PLG_PAGENAVIGATION_FIELD_VALUE_ABOVE</option>
				</field>

				<field
					name="relative"
					type="list"
					label="PLG_PAGENAVIGATION_FIELD_RELATIVE_LABEL"
					description="PLG_PAGENAVIGATION_FIELD_RELATIVE_DESC"
					default="1"
					filter="integer"
					>
					<option
value="1">PLG_PAGENAVIGATION_FIELD_VALUE_ARTICLE</option>
					<option
value="0">PLG_PAGENAVIGATION_FIELD_VALUE_TEXT</option>
				</field>

				<field
					name="display"
					type="list"
					label="PLG_PAGENAVIGATION_FIELD_DISPLAY_LABEL"
					description="PLG_PAGENAVIGATION_FIELD_DISPLAY_DESC"
					default="0"
					filter="integer"
					>
					<option
value="0">PLG_PAGENAVIGATION_FIELD_VALUE_NEXTPREV</option>
					<option
value="1">PLG_PAGENAVIGATION_FIELD_VALUE_TITLE</option>
				</field>

			</fieldset>
		</fields>
	</config>
</extension>
content/pagenavigation/tmpl/default.php000064400000002577147357022240014344
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.pagenavigation
 *
 * @copyright   (C) 2013 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('bootstrap.tooltip');

$lang = JFactory::getLanguage();

?>
<ul class="pager pagenav">
<?php if ($row->prev) :
	$direction = $lang->isRtl() ? 'right' : 'left';
?>
	<li class="previous">
		<a class="hasTooltip" title="<?php echo
htmlspecialchars($rows[$location-1]->title); ?>"
aria-label="<?php echo JText::sprintf('JPREVIOUS_TITLE',
htmlspecialchars($rows[$location-1]->title)); ?>"
href="<?php echo $row->prev; ?>"
rel="prev">
			<?php echo '<span class="icon-chevron-' .
$direction . '" aria-hidden="true"></span>
<span aria-hidden="true">' . $row->prev_label .
'</span>'; ?>
		</a>
	</li>
<?php endif; ?>
<?php if ($row->next) :
	$direction = $lang->isRtl() ? 'left' : 'right';
?>
	<li class="next">
		<a class="hasTooltip" title="<?php echo
htmlspecialchars($rows[$location+1]->title); ?>"
aria-label="<?php echo JText::sprintf('JNEXT_TITLE',
htmlspecialchars($rows[$location+1]->title)); ?>"
href="<?php echo $row->next; ?>"
rel="next">
			<?php echo '<span aria-hidden="true">' .
$row->next_label . '</span> <span
class="icon-chevron-' . $direction . '"
aria-hidden="true"></span>'; ?>
		</a>
	</li>
<?php endif; ?>
</ul>
content/vote/tmpl/rating.php000064400000003167147357022240012161
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.vote
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Layout variables
 * -----------------
 * @var   string   $context  The context of the content being passed to the
plugin
 * @var   object   &$row     The article object
 * @var   object   &$params  The article params
 * @var   integer  $page     The 'page' number
 * @var   array    $parts    The context segments
 * @var   string   $path     Path to this file
 */

if ($context == 'com_content.categories')
{
	return;
}

$rating = (int) $row->rating;
$rcount = (int) $row->rating_count;

// Look for images in template if available
$starImageOn  = JHtml::_('image',
'system/rating_star.png',
JText::_('PLG_VOTE_STAR_ACTIVE'), null, true);
$starImageOff = JHtml::_('image',
'system/rating_star_blank.png',
JText::_('PLG_VOTE_STAR_INACTIVE'), null, true);

$img = '';

for ($i = 0; $i < $rating; $i++)
{
	$img .= $starImageOn;
}

for ($i = $rating; $i < 5; $i++)
{
	$img .= $starImageOff;
}

?>
<div class="content_rating">
	<?php if ($rcount) : ?>
		<p class="unseen element-invisible"
itemprop="aggregateRating" itemscope
itemtype="https://schema.org/AggregateRating">
			<?php echo JText::sprintf('PLG_VOTE_USER_RATING',
'<span itemprop="ratingValue">' . $rating .
'</span>', '<span
itemprop="bestRating">5</span>'); ?>
			<meta itemprop="ratingCount" content="<?php echo
$rcount; ?>" />
			<meta itemprop="worstRating" content="1" />
		</p>
	<?php endif; ?>
	<?php echo $img; ?>
</div>
content/vote/tmpl/vote.php000064400000003257147357022240011652
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.vote
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Layout variables
 * -----------------
 * @var   string   $context  The context of the content being passed to the
plugin
 * @var   object   &$row     The article object
 * @var   object   &$params  The article params
 * @var   integer  $page     The 'page' number
 * @var   array    $parts    The context segments
 * @var   string   $path     Path to this file
 */

$uri = clone JUri::getInstance();
$uri->setVar('hitcount', '0');

// Create option list for voting select box
$options = array();

for ($i = 1; $i < 6; $i++)
{
	$options[] = JHtml::_('select.option', $i,
JText::sprintf('PLG_VOTE_VOTE', $i));
}

?>
<form method="post" action="<?php echo
htmlspecialchars($uri->toString(), ENT_COMPAT, 'UTF-8');
?>" class="form-inline">
	<span class="content_vote">
		<label class="unseen element-invisible"
for="content_vote_<?php echo (int) $row->id;
?>"><?php echo JText::_('PLG_VOTE_LABEL');
?></label>
		<?php echo JHtml::_('select.genericlist', $options,
'user_rating', null, 'value', 'text',
'5', 'content_vote_' . (int) $row->id); ?>
		&#160;<input class="btn btn-mini"
type="submit" name="submit_vote" value="<?php
echo JText::_('PLG_VOTE_RATE'); ?>" />
		<input type="hidden" name="task"
value="article.vote" />
		<input type="hidden" name="hitcount"
value="0" />
		<input type="hidden" name="url"
value="<?php echo htmlspecialchars($uri->toString(), ENT_COMPAT,
'UTF-8'); ?>" />
		<?php echo JHtml::_('form.token'); ?>
	</span>
</form>
content/vote/vote.php000064400000007152147357022240010674 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Content.vote
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Vote plugin.
 *
 * @since  1.5
 */
class PlgContentVote extends JPlugin
{
	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 * @since  3.7.0
	 */
	protected $app;

	/**
	 * The position the voting data is displayed in relative to the article.
	 *
	 * @var    string
	 * @since  3.7.0
	 */
	protected $votingPosition;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An optional associative array of
configuration settings.
	 *
	 * @since   3.7.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		$this->votingPosition = $this->params->get('position',
'top');
	}

	/**
	 * Displays the voting area when viewing an article and the voting section
is displayed before the article
	 *
	 * @param   string   $context  The context of the content being passed to
the plugin
	 * @param   object   &$row     The article object
	 * @param   object   &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  string|boolean  HTML string containing code for the votes if
in com_content else boolean false
	 *
	 * @since   1.6
	 */
	public function onContentBeforeDisplay($context, &$row, &$params,
$page = 0)
	{
		if ($this->votingPosition !== 'top')
		{
			return '';
		}

		return $this->displayVotingData($context, $row, $params, $page);
	}

	/**
	 * Displays the voting area when viewing an article and the voting section
is displayed after the article
	 *
	 * @param   string   $context  The context of the content being passed to
the plugin
	 * @param   object   &$row     The article object
	 * @param   object   &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  string|boolean  HTML string containing code for the votes if
in com_content else boolean false
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterDisplay($context, &$row, &$params,
$page = 0)
	{
		if ($this->votingPosition !== 'bottom')
		{
			return '';
		}

		return $this->displayVotingData($context, $row, $params, $page);
	}

	/**
	 * Displays the voting area
	 *
	 * @param   string   $context  The context of the content being passed to
the plugin
	 * @param   object   &$row     The article object
	 * @param   object   &$params  The article params
	 * @param   integer  $page     The 'page' number
	 *
	 * @return  string|boolean  HTML string containing code for the votes if
in com_content else boolean false
	 *
	 * @since   3.7.0
	 */
	private function displayVotingData($context, &$row, &$params,
$page)
	{
		$parts = explode('.', $context);

		if ($parts[0] !== 'com_content')
		{
			return false;
		}

		if (empty($params) || !$params->get('show_vote', null))
		{
			return '';
		}

		// Load plugin language files only when needed (ex: they are not needed
if show_vote is not active).
		$this->loadLanguage();

		// Get the path for the rating summary layout file
		$path = JPluginHelper::getLayoutPath('content',
'vote', 'rating');

		// Render the layout
		ob_start();
		include $path;
		$html = ob_get_clean();

		if ($this->app->input->getString('view', '')
=== 'article' && $row->state == 1)
		{
			// Get the path for the voting form layout file
			$path = JPluginHelper::getLayoutPath('content',
'vote', 'vote');

			// Render the layout
			ob_start();
			include $path;
			$html .= ob_get_clean();
		}

		return $html;
	}
}
content/vote/vote.xml000064400000002176147357022240010706 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="content" method="upgrade">
	<name>plg_content_vote</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_VOTE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="vote">vote.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_content_vote.ini</language>
		<language
tag="en-GB">en-GB.plg_content_vote.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="position"
					type="list"
					label="PLG_VOTE_POSITION_LABEL"
					description="PLG_VOTE_POSITION_DESC"
					default="top"
					>
					<option value="top">PLG_VOTE_TOP</option>
					<option value="bottom">PLG_VOTE_BOTTOM</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
editors/codemirror/codemirror.php000064400000024473147357022240013260
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2009 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

/**
 * CodeMirror Editor Plugin.
 *
 * @since  1.6
 */
class PlgEditorCodemirror extends JPlugin
{
	/**
	 * Affects constructor behavior. If true, language files will be loaded
automatically.
	 *
	 * @var    boolean
	 * @since  3.1.4
	 */
	protected $autoloadLanguage = true;

	/**
	 * Mapping of syntax to CodeMirror modes.
	 *
	 * @var array
	 */
	protected $modeAlias = array();

	/**
	 * Initialises the Editor.
	 *
	 * @return  void
	 */
	public function onInit()
	{
		static $done = false;

		// Do this only once.
		if ($done)
		{
			return;
		}

		$done = true;

		// Most likely need this later
		$doc = JFactory::getDocument();

		// Codemirror shall have its own group of plugins to modify and extend
its behavior
		JPluginHelper::importPlugin('editors_codemirror');
		$dispatcher	= JEventDispatcher::getInstance();

		// At this point, params can be modified by a plugin before going to the
layout renderer.
		$dispatcher->trigger('onCodeMirrorBeforeInit',
array(&$this->params));

		$displayData = (object) array('params'  =>
$this->params);

		// We need to do output buffering here because layouts may actually
'echo' things which we do not want.
		ob_start();
		JLayoutHelper::render('editors.codemirror.init', $displayData,
__DIR__ . '/layouts');
		ob_end_clean();

		$font = $this->params->get('fontFamily', '0');
		$fontInfo = $this->getFontInfo($font);

		if (isset($fontInfo))
		{
			if (isset($fontInfo->url))
			{
				$doc->addStyleSheet($fontInfo->url);
			}

			if (isset($fontInfo->css))
			{
				$displayData->fontFamily = $fontInfo->css .
'!important';
			}
		}

		// We need to do output buffering here because layouts may actually
'echo' things which we do not want.
		ob_start();
		JLayoutHelper::render('editors.codemirror.styles',
$displayData, __DIR__ . '/layouts');
		ob_end_clean();

		$dispatcher->trigger('onCodeMirrorAfterInit',
array(&$this->params));
	}

	/**
	 * Copy editor content to form field.
	 *
	 * @param   string  $id  The id of the editor field.
	 *
	 * @return  string  Javascript
	 *
	 * @deprecated 4.0 Code executes directly on submit
	 */
	public function onSave($id)
	{
		return sprintf('document.getElementById(%1$s).value =
Joomla.editors.instances[%1$s].getValue();', json_encode((string)
$id));
	}

	/**
	 * Get the editor content.
	 *
	 * @param   string  $id  The id of the editor field.
	 *
	 * @return  string  Javascript
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onGetContent($id)
	{
		return sprintf('Joomla.editors.instances[%1$s].getValue();',
json_encode((string) $id));
	}

	/**
	 * Set the editor content.
	 *
	 * @param   string  $id       The id of the editor field.
	 * @param   string  $content  The content to set.
	 *
	 * @return  string  Javascript
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSetContent($id, $content)
	{
		return
sprintf('Joomla.editors.instances[%1$s].setValue(%2$s);',
json_encode((string) $id), json_encode((string) $content));
	}

	/**
	 * Adds the editor specific insert method.
	 *
	 * @return  void
	 *
	 * @deprecated 4.0 Code is loaded in the init script
	 */
	public function onGetInsertMethod()
	{
		static $done = false;

		// Do this only once.
		if ($done)
		{
			return true;
		}

		$done = true;

		JFactory::getDocument()->addScriptDeclaration("
		;function jInsertEditorText(text, editor) {
Joomla.editors.instances[editor].replaceSelection(text); }
		");

		return true;
	}

	/**
	 * Display the editor area.
	 *
	 * @param   string   $name     The control name.
	 * @param   string   $content  The contents of the text area.
	 * @param   string   $width    The width of the text area (px or %).
	 * @param   string   $height   The height of the text area (px or %).
	 * @param   int      $col      The number of columns for the textarea.
	 * @param   int      $row      The number of rows for the textarea.
	 * @param   boolean  $buttons  True and the editor buttons will be
displayed.
	 * @param   string   $id       An optional ID for the textarea (note:
since 1.6). If not supplied the name is used.
	 * @param   string   $asset    Not used.
	 * @param   object   $author   Not used.
	 * @param   array    $params   Associative array of editor parameters.
	 *
	 * @return  string  HTML
	 */
	public function onDisplay(
		$name, $content, $width, $height, $col, $row, $buttons = true, $id =
null, $asset = null, $author = null, $params = array())
	{
		// True if a CodeMirror already has autofocus. Prevent multiple
autofocuses.
		static $autofocused;

		$id = empty($id) ? $name : $id;

		// Must pass the field id to the buttons in this editor.
		$buttons = $this->displayButtons($id, $buttons, $asset, $author);

		// Only add "px" to width and height if they are not given as a
percentage.
		$width .= is_numeric($width) ? 'px' : '';
		$height .= is_numeric($height) ? 'px' : '';

		// Options for the CodeMirror constructor.
		$options = new stdClass;

		// Is field readonly?
		if (!empty($params['readonly']))
		{
			$options->readOnly = 'nocursor';
		}

		// Should we focus on the editor on load?
		if (!$autofocused)
		{
			$options->autofocus = isset($params['autofocus']) ? (bool)
$params['autofocus'] : false;
			$autofocused = $options->autofocus;
		}

		$options->lineWrapping = (boolean)
$this->params->get('lineWrapping', 1);

		// Add styling to the active line.
		$options->styleActiveLine = (boolean)
$this->params->get('activeLine', 1);

		// Do we highlight selection matches?
		if ($this->params->get('selectionMatches', 1))
		{
			$options->highlightSelectionMatches = array(
					'showToken' => true,
					'annotateScrollbar' => true,
				);
		}

		// Do we use line numbering?
		if ($options->lineNumbers = (boolean)
$this->params->get('lineNumbers', 1))
		{
			$options->gutters[] = 'CodeMirror-linenumbers';
		}

		// Do we use code folding?
		if ($options->foldGutter = (boolean)
$this->params->get('codeFolding', 1))
		{
			$options->gutters[] = 'CodeMirror-foldgutter';
		}

		// Do we use a marker gutter?
		if ($options->markerGutter = (boolean)
$this->params->get('markerGutter',
$this->params->get('marker-gutter', 1)))
		{
			$options->gutters[] = 'CodeMirror-markergutter';
		}

		// Load the syntax mode.
		$syntax = !empty($params['syntax'])
			? $params['syntax']
			: $this->params->get('syntax', 'html');
		$options->mode = isset($this->modeAlias[$syntax]) ?
$this->modeAlias[$syntax] : $syntax;

		// Load the theme if specified.
		if ($theme = $this->params->get('theme'))
		{
			$options->theme = $theme;
			JHtml::_('stylesheet',
$this->params->get('basePath',
'media/editors/codemirror/') . 'theme/' . $theme .
'.css', array('version' => 'auto'));
		}

		// Special options for tagged modes (xml/html).
		if (in_array($options->mode, array('xml', 'html',
'php')))
		{
			// Autogenerate closing tags (html/xml only).
			$options->autoCloseTags = (boolean)
$this->params->get('autoCloseTags', 1);

			// Highlight the matching tag when the cursor is in a tag (html/xml
only).
			$options->matchTags = (boolean)
$this->params->get('matchTags', 1);
		}

		// Special options for non-tagged modes.
		if (!in_array($options->mode, array('xml',
'html')))
		{
			// Autogenerate closing brackets.
			$options->autoCloseBrackets = (boolean)
$this->params->get('autoCloseBrackets', 1);

			// Highlight the matching bracket.
			$options->matchBrackets = (boolean)
$this->params->get('matchBrackets', 1);
		}

		$options->scrollbarStyle =
$this->params->get('scrollbarStyle', 'native');

		// KeyMap settings.
		$options->keyMap = $this->params->get('keyMap',
false);

		// Support for older settings.
		if ($options->keyMap === false)
		{
			$options->keyMap =
$this->params->get('vimKeyBinding', 0) ? 'vim' :
'default';
		}

		if ($options->keyMap && $options->keyMap !=
'default')
		{
			$this->loadKeyMap($options->keyMap);
		}

		$displayData = (object) array(
				'options' => $options,
				'params'  => $this->params,
				'name'    => $name,
				'id'      => $id,
				'cols'    => $col,
				'rows'    => $row,
				'content' => $content,
				'buttons' => $buttons
			);

		$dispatcher = JEventDispatcher::getInstance();

		// At this point, displayData can be modified by a plugin before going to
the layout renderer.
		$results = $dispatcher->trigger('onCodeMirrorBeforeDisplay',
array(&$displayData));

		$results[] =
JLayoutHelper::render('editors.codemirror.element', $displayData,
__DIR__ . '/layouts', array('debug' => JDEBUG));

		foreach ($dispatcher->trigger('onCodeMirrorAfterDisplay',
array(&$displayData)) as $result)
		{
			$results[] = $result;
		}

		return implode("\n", $results);
	}

	/**
	 * Displays the editor buttons.
	 *
	 * @param   string  $name     Button name.
	 * @param   mixed   $buttons  [array with button objects | boolean true to
display buttons]
	 * @param   mixed   $asset    Unused.
	 * @param   mixed   $author   Unused.
	 *
	 * @return  string  HTML
	 */
	protected function displayButtons($name, $buttons, $asset, $author)
	{
		$return = '';

		$args = array(
			'name'  => $name,
			'event' => 'onGetInsertMethod'
		);

		$results = (array) $this->update($args);

		if ($results)
		{
			foreach ($results as $result)
			{
				if (is_string($result) && trim($result))
				{
					$return .= $result;
				}
			}
		}

		if (is_array($buttons) || (is_bool($buttons) && $buttons))
		{
			$buttons = $this->_subject->getButtons($name, $buttons, $asset,
$author);

			$return .= JLayoutHelper::render('joomla.editors.buttons',
$buttons);
		}

		return $return;
	}

	/**
	 * Gets font info from the json data file
	 *
	 * @param   string  $font  A key from the $fonts array.
	 *
	 * @return  object
	 */
	protected function getFontInfo($font)
	{
		static $fonts;

		if (!$fonts)
		{
			$fonts = json_decode(file_get_contents(__DIR__ .
'/fonts.json'), true);
		}

		return isset($fonts[$font]) ? (object) $fonts[$font] : null;
	}

	/**
	 * Loads a keyMap file
	 *
	 * @param   string  $keyMap  The name of a keyMap file to load.
	 *
	 * @return  void
	 */
	protected function loadKeyMap($keyMap)
	{
		$basePath = $this->params->get('basePath',
'media/editors/codemirror/');
		$ext = JDEBUG ? '.js' : '.min.js';
		JHtml::_('script', $basePath . 'keymap/' . $keyMap .
$ext, array('version' => 'auto'));
	}
}
editors/codemirror/codemirror.xml000064400000024674147357022240013274
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin"
group="editors" method="upgrade">
	<name>plg_editors_codemirror</name>
	<version>5.60.0</version>
	<creationDate>28 March 2011</creationDate>
	<author>Marijn Haverbeke</author>
	<authorEmail>marijnh@gmail.com</authorEmail>
	<authorUrl>https://codemirror.net/</authorUrl>
	<copyright>Copyright (C) 2014 - 2021 by Marijn Haverbeke
&lt;marijnh@gmail.com&gt; and others</copyright>
	<license>MIT license: https://codemirror.net/LICENSE</license>
	<description>PLG_CODEMIRROR_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="codemirror">codemirror.php</filename>
		<filename>styles.css</filename>
		<filename>styles.min.css</filename>
		<filename>fonts.json</filename>
		<filename>fonts.php</filename>
	</files>

	<languages>
		<language
tag="en-GB">en-GB.plg_editors_codemirror.ini</language>
		<language
tag="en-GB">en-GB.plg_editors_codemirror.sys.ini</language>
	</languages>

	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="lineNumbers"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_LINENUMBERS_LABEL"
					description="PLG_CODEMIRROR_FIELD_LINENUMBERS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="codeFolding"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_CODEFOLDING_LABEL"
					description="PLG_CODEMIRROR_FIELD_CODEFOLDING_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="markerGutter"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_MARKERGUTTER_LABEL"
					description="PLG_CODEMIRROR_FIELD_MARKERGUTTER_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="lineWrapping"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_LINEWRAPPING_LABEL"
					description="PLG_CODEMIRROR_FIELD_LINEWRAPPING_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="activeLine"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_ACTIVELINE_LABEL"
					description="PLG_CODEMIRROR_FIELD_ACTIVELINE_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="selectionMatches"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_SELECTIONMATCHES_LABEL"
					description="PLG_CODEMIRROR_FIELD_SELECTIONMATCHES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="matchTags"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_MATCHTAGS_LABEL"
					description="PLG_CODEMIRROR_FIELD_MATCHTAGS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="matchBrackets"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_MATCHBRACKETS_LABEL"
					description="PLG_CODEMIRROR_FIELD_MATCHBRACKETS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="autoCloseTags"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_AUTOCLOSETAGS_LABEL"
					description="PLG_CODEMIRROR_FIELD_AUTOCLOSETAGS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="autoCloseBrackets"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_AUTOCLOSEBRACKET_LABEL"
					description="PLG_CODEMIRROR_FIELD_AUTOCLOSEBRACKET_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>

				<field
					name="keyMap"
					type="list"
					label="PLG_CODEMIRROR_FIELD_KEYMAP_LABEL"
					description="PLG_CODEMIRROR_FIELD_KEYMAP_DESC"
					default=""
					>
					<option value="">JDEFAULT</option>
					<option
value="emacs">PLG_CODEMIRROR_FIELD_KEYMAP_EMACS</option>
					<option
value="sublime">PLG_CODEMIRROR_FIELD_KEYMAP_SUBLIME</option>
					<option
value="vim">PLG_CODEMIRROR_FIELD_KEYMAP_VIM</option>
				</field>

				<field
					name="fullScreen"
					type="list"
					label="PLG_CODEMIRROR_FIELD_FULLSCREEN_LABEL"
					description="PLG_CODEMIRROR_FIELD_FULLSCREEN_DESC"
					default="F10"
					>
					<option value="F1">F1</option>
					<option value="F2">F2</option>
					<option value="F3">F3</option>
					<option value="F4">F4</option>
					<option value="F5">F5</option>
					<option value="F6">F6</option>
					<option value="F7">F7</option>
					<option value="F8">F8</option>
					<option value="F9">F9</option>
					<option value="F10">F10</option>
					<option value="F11">F11</option>
					<option value="F12">F12</option>
				</field>

				<field
					name="fullScreenMod"
					type="checkboxes"
					label="PLG_CODEMIRROR_FIELD_FULLSCREEN_MOD_LABEL"
					description="PLG_CODEMIRROR_FIELD_FULLSCREEN_MOD_DESC"
					>
					<option
value="Shift">PLG_CODEMIRROR_FIELD_VALUE_FULLSCREEN_MOD_SHIFT</option>
					<option
value="Cmd">PLG_CODEMIRROR_FIELD_VALUE_FULLSCREEN_MOD_CMD</option>
					<option
value="Ctrl">PLG_CODEMIRROR_FIELD_VALUE_FULLSCREEN_MOD_CTRL</option>
					<option
value="Alt">PLG_CODEMIRROR_FIELD_VALUE_FULLSCREEN_MOD_ALT</option>
				</field>

				<field
					name="basePath"
					type="hidden"
					default="media/editors/codemirror/"
				/>

				<field
					name="modePath"
					type="hidden"
					default="media/editors/codemirror/mode/%N/%N"
				/>
			</fieldset>

			<fieldset name="appearance"
label="PLG_CODEMIRROR_FIELDSET_APPEARANCE_OPTIONS_LABEL"
addfieldpath="plugins/editors/codemirror">
				<field
					name="theme"
					type="filelist"
					label="PLG_CODEMIRROR_FIELD_THEME_LABEL"
					description="PLG_CODEMIRROR_FIELD_THEME_DESC"
					default=""
					filter="\.css$"
					stripext="true"
					hide_none="true"
					hide_default="false"
					directory="media/editors/codemirror/theme"
				/>

				<field
					name="activeLineColor"
					type="color"
					label="PLG_CODEMIRROR_FIELD_ACTIVELINE_COLOR_LABEL"
					description="PLG_CODEMIRROR_FIELD_ACTIVELINE_COLOR_DESC"
					default="#a4c2eb"
					filter="color"
				/>

				<field
					name="highlightMatchColor"
					type="color"
					label="PLG_CODEMIRROR_FIELD_HIGHLIGHT_MATCH_COLOR_LABEL"
					description="PLG_CODEMIRROR_FIELD_HIGHLIGHT_MATCH_COLOR_DESC"
					default="#fa542f"
					filter="color"
				/>

				<field
					name="fontFamily"
					type="fonts"
					label="PLG_CODEMIRROR_FIELD_FONT_FAMILY_LABEL"
					description="PLG_CODEMIRROR_FIELD_FONT_FAMILY_DESC"
					default="0"
					>
					<option
value="0">PLG_CODEMIRROR_FIELD_VALUE_FONT_FAMILY_DEFAULT</option>
				</field>

				<field
					name="fontSize"
					type="integer"
					label="PLG_CODEMIRROR_FIELD_FONT_SIZE_LABEL"
					description="PLG_CODEMIRROR_FIELD_FONT_SIZE_DESC"
					first="6"
					last="16"
					step="1"
					default="13"
					filter="integer"
				/>

				<field
					name="lineHeight"
					type="list"
					label="PLG_CODEMIRROR_FIELD_LINE_HEIGHT_LABEL"
					description="PLG_CODEMIRROR_FIELD_LINE_HEIGHT_DESC"
					default="1.2"
					filter="float"
					>
					<option value="1">1</option>
					<option value="1.1">1.1</option>
					<option value="1.2">1.2</option>
					<option value="1.3">1.3</option>
					<option value="1.4">1.4</option>
					<option value="1.5">1.5</option>
					<option value="1.6">1.6</option>
					<option value="1.7">1.7</option>
					<option value="1.8">1.8</option>
					<option value="1.9">1.9</option>
					<option value="2">2</option>
				</field>

				<field
					name="scrollbarStyle"
					type="radio"
					label="PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_LABEL"
					description="PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_DESC"
					class="btn-group btn-group-yesno"
					default="native"
					>
					<option
value="native">PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_DEFAULT</option>
					<option
value="simple">PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_SIMPLE</option>
					<option
value="overlay">PLG_CODEMIRROR_FIELD_VALUE_SCROLLBARSTYLE_OVERLAY</option>
				</field>

				<field
					name="preview"
					type="editor"
					label="PLG_CODEMIRROR_FIELD_PREVIEW_LABEL"
					description="PLG_CODEMIRROR_FIELD_PREVIEW_DESC"
					editor="codemirror"
					filter="unset"
					buttons="false"
					>
					<default>
<![CDATA[
<script type="text/javascript">
	jQuery(function ($) {
		$('.hello').html('Hello World');
	});
</script>

<style type="text/css">
	h1 {
		background-clip: border-box;
		background-color: #cacaff;
		background-image: linear-gradient(45deg, transparent 0px, transparent
30px, #ababff 30px, #ababff 60px, transparent 60px);
		background-repeat: repeat-x;
		background-size: 90px 100%;
		border: 1px solid #8989ff;
		border-radius: 10px;
		color: #333;
		padding: 0 15px;
	}
</style>

<div>
	<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam
a ornare lectus, quis semper urna. Vestibulum ante ipsum primis in faucibus
orci luctus et ultrices posuere cubilia Curae; Vivamus interdum metus id
elit rutrum sollicitudin. Pellentesque habitant morbi tristique senectus et
netus et malesuada fames ac turpis egestas. Aliquam in fermentum risus, id
facilisis nulla. Phasellus gravida erat sed ullamcorper accumsan. Donec
blandit sem eget sem congue, a varius sapien semper.</p>
	<p>Integer euismod tempor convallis. Nullam porttitor et ex ac
fringilla. Quisque facilisis est ac erat condimentum malesuada. Aenean
commodo quam odio, tincidunt ultricies mauris suscipit et.</p>

	<ul>
		<li>Vivamus ultrices ligula a odio lacinia pellentesque.</li>
		<li>Curabitur iaculis arcu pharetra, mollis turpis id, commodo
erat.</li>
		<li>Etiam consequat enim quis faucibus interdum.</li>
		<li>Morbi in ipsum pulvinar, eleifend lorem sit amet, euismod
magna.</li>
		<li>Donec consectetur lacus vitae eros euismod porta.</li>
	</ul>
</div>
]]>
					</default>
				</field>

			</fieldset>
		</fields>
	</config>
</extension>
editors/codemirror/fonts.json000064400000006055147357022240012422 0ustar00{
	"anonymous_pro": {
		"name": "Anonymous Pro",
		"url":
"https://fonts.googleapis.com/css?family=Anonymous+Pro",
		"css": "'Anonymous Pro', monospace"
	},
	"cousine": {
		"name": "Cousine",
		"url":
"https://fonts.googleapis.com/css?family=Cousine",
		"css": "Cousine, monospace"
	},
	"cutive_mono": {
		"name": "Cutive Mono",
		"url":
"https://fonts.googleapis.com/css?family=Cutive+Mono",
		"css": "'Cutive Mono', monospace"
	},
	"droid_sans_mono": {
		"name": "Droid Sans Mono",
		"url":
"https://fonts.googleapis.com/css?family=Droid+Sans+Mono",
		"css": "'Droid Sans Mono', monospace"
	},
	"fira_mono": {
		"name": "Fira Mono",
		"url":
"https://fonts.googleapis.com/css?family=Fira+Mono",
		"css": "'Fira Mono', monospace"
	},
	"ibm_plex_mono": {
		"name": "IBM Plex Mono",
		"url":
"https://fonts.googleapis.com/css?family=IBM+Plex+Mono",
		"css": "'IBM Plex Mono', monospace;"
	},
	"inconsolata": {
		"name": "Inconsolata",
		"url":
"https://fonts.googleapis.com/css?family=Inconsolata",
		"css": "Inconsolata, monospace"
	},
	"lekton": {
		"name": "Lekton",
		"url":
"https://fonts.googleapis.com/css?family=Lekton",
		"css": "Lekton, monospace"
	},
	"nanum_gothic_coding": {
		"name": "Nanum Gothic Coding",
		"url":
"https://fonts.googleapis.com/css?family=Nanum+Gothic+Coding",
		"css": "'Nanum Gothic Coding', monospace"
	},
	"nova_mono": {
		"name": "Nova Mono",
		"url":
"https://fonts.googleapis.com/css?family=Nova+Mono",
		"css": "'Nova Mono', monospace"
	},
	"overpass_mono": {
		"name": "Overpass Mono",
		"url":
"https://fonts.googleapis.com/css?family=Overpass+Mono",
		"css": "'Overpass Mono', monospace"
	},
	"oxygen_mono": {
		"name": "Oxygen Mono",
		"url":
"https://fonts.googleapis.com/css?family=Oxygen+Mono",
		"css": "'Oxygen Mono', monospace"
	},
	"press_start_2p": {
		"name": "Press Start 2P",
		"url":
"https://fonts.googleapis.com/css?family=Press+Start+2P",
		"css": "'Press Start 2P', monospace"
	},
	"pt_mono": {
		"name": "PT Mono",
		"url":
"https://fonts.googleapis.com/css?family=PT+Mono",
		"css": "'PT Mono', monospace"
	},
	"roboto_mono": {
		"name": "Roboto Mono",
		"url":
"https://fonts.googleapis.com/css?family=Roboto+Mono",
		"css": "'Roboto Mono', monospace"
	},
	"rubik_mono_one": {
		"name": "Rubik Mono One",
		"url":
"https://fonts.googleapis.com/css?family=Rubik+Mono+One",
		"css": "'Rubik Mono One', monospace"
	},
	"share_tech_mono": {
		"name": "Share Tech Mono",
		"url":
"https://fonts.googleapis.com/css?family=Share+Tech+Mono",
		"css": "'Share Tech Mono', monospace"
	},
	"source_code_pro": {
		"name": "Source Code Pro",
		"url":
"https://fonts.googleapis.com/css?family=Source+Code+Pro",
		"css": "'Source Code Pro', monospace"
	},
	"space_mono": {
		"name": "Space Mono",
		"url":
"https://fonts.googleapis.com/css?family=Space+Mono",
		"css": "'Space Mono', monospace"
	},
	"ubuntu_mono": {
		"name": "Ubuntu Mono",
		"url":
"https://fonts.googleapis.com/css?family=Ubuntu+Mono",
		"css": "'Ubuntu Mono', monospace"
	},
	"vt323": {
		"name": "VT323",
		"url":
"https://fonts.googleapis.com/css?family=VT323",
		"css": "'VT323', monospace"
	}
}
editors/codemirror/fonts.php000064400000002104147357022240012227
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2014 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

JFormHelper::loadFieldClass('list');

/**
 * Supports an HTML select list of fonts
 *
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 * @since       3.4
 */
class JFormFieldFonts extends JFormFieldList
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.4
	 */
	protected $type = 'Fonts';

	/**
	 * Method to get the list of fonts field options.
	 *
	 * @return  array  The field option objects.
	 *
	 * @since   3.4
	 */
	protected function getOptions()
	{
		$fonts = json_decode(file_get_contents(__DIR__ .
'/fonts.json'));
		$options = array();

		foreach ($fonts as $key => $info)
		{
			$options[] = JHtml::_('select.option', $key, $info->name);
		}

		// Merge any additional options in the XML definition.
		return array_merge(parent::getOptions(), $options);
	}
}
editors/codemirror/layouts/editors/codemirror/element.php000064400000002052147357022240020047
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

$options  = $displayData->options;
$params   = $displayData->params;
$name     = $displayData->name;
$id       = $displayData->id;
$cols     = $displayData->cols;
$rows     = $displayData->rows;
$content  = $displayData->content;
$buttons  = $displayData->buttons;
$modifier = $params->get('fullScreenMod', array()) ?
implode(' + ', $params->get('fullScreenMod',
array())) . ' + ' : '';

?>

<p class="label">
    <?php echo
JText::sprintf('PLG_CODEMIRROR_TOGGLE_FULL_SCREEN', $modifier,
$params->get('fullScreen', 'F10')); ?>
</p>

<?php
	echo '<textarea class="codemirror-source"
name="', $name,
		'" id="', $id,
		'" cols="', $cols,
		'" rows="', $rows,
		'" data-options="',
htmlspecialchars(json_encode($options)),
		'">', $content, '</textarea>';
?>

<?php echo $buttons; ?>
editors/codemirror/layouts/editors/codemirror/init.php000064400000007243147357022240017370
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

$params   = $displayData->params;
$basePath = $params->get('basePath',
'media/editors/codemirror/');
$modePath = $params->get('modePath',
'media/editors/codemirror/mode/%N/%N');
$extJS    = JDEBUG ? '.js' : '.min.js';
$extCSS   = JDEBUG ? '.css' : '.min.css';

JHtml::_('script', $basePath . 'lib/codemirror' .
$extJS, array('version' => 'auto'));
JHtml::_('script', $basePath . 'lib/addons' . $extJS,
array('version' => 'auto'));
JHtml::_('stylesheet', $basePath . 'lib/codemirror' .
$extCSS, array('version' => 'auto'));
JHtml::_('stylesheet', $basePath . 'lib/addons' .
$extCSS, array('version' => 'auto'));

$fskeys          = $params->get('fullScreenMod', array());
$fskeys[]        = $params->get('fullScreen',
'F10');
$fullScreenCombo = implode('-', $fskeys);
$fsCombo         = json_encode($fullScreenCombo);
$modPath         = json_encode(JUri::root(true) . '/' . $modePath
. $extJS);
JFactory::getDocument()->addScriptDeclaration(
<<<JS
		;(function (cm, $) {
			cm.commands.toggleFullScreen = function (cm) {
				cm.setOption('fullScreen',
!cm.getOption('fullScreen'));
			};
			cm.commands.closeFullScreen = function (cm) {
				cm.getOption('fullScreen') &&
cm.setOption('fullScreen', false);
			};

			cm.keyMap.default['Ctrl-Q'] = 'toggleFullScreen';
			cm.keyMap.default[$fsCombo] = 'toggleFullScreen';
			cm.keyMap.default['Esc'] = 'closeFullScreen';
			// For mode autoloading.
			cm.modeURL = $modPath;
			// Fire this function any time an editor is created.
			cm.defineInitHook(function (editor)
			{
				// Try to set up the mode
				var mode = cm.findModeByMIME(editor.options.mode || '') ||
							cm.findModeByName(editor.options.mode || '') ||
							cm.findModeByExtension(editor.options.mode || '');

				cm.autoLoadMode(editor, mode ? mode.mode : editor.options.mode);

				if (mode && mode.mime)
				{
					editor.setOption('mode', mode.mime);
				}

				// Handle gutter clicks (place or remove a marker).
				editor.on('gutterClick', function (ed, n, gutter) {
					if (gutter != 'CodeMirror-markergutter') { return; }
					var info = ed.lineInfo(n),
						hasMarker = !!info.gutterMarkers &&
!!info.gutterMarkers['CodeMirror-markergutter'];
					ed.setGutterMarker(n, 'CodeMirror-markergutter', hasMarker ?
null : makeMarker());
				});

				// jQuery's ready function.
				$(function () {
					// Some browsers do something weird with the fieldset which
doesn't work well with CodeMirror. Fix it.
					$(editor.getWrapperElement()).parent('fieldset').css('min-width',
0);
					// Listen for Bootstrap's 'shown' event. If this editor
was in a hidden element when created, it may need to be refreshed.
					$(document.body).on('shown shown.bs.tab shown.bs.modal',
function () { editor.refresh(); });
				});
			});

			function makeMarker()
			{
				var marker = document.createElement('div');
				marker.className = 'CodeMirror-markergutter-mark';
				return marker;
			}

			// Initialize any CodeMirrors on page load and when a subform is added
			$(function ($) {
				initCodeMirror();
				$('body').on('subform-row-add', initCodeMirror);
			});

			function initCodeMirror(event, container)
			{
				container = container || document;
				$(container).find('textarea.codemirror-source').each(function
() {
					var input = $(this).removeClass('codemirror-source');
					var id = input.prop('id');

					Joomla.editors.instances[id] = cm.fromTextArea(this,
input.data('options'));
				});
			}

		}(CodeMirror, jQuery));
JS
);
editors/codemirror/layouts/editors/codemirror/styles.php000064400000004502147357022240017743
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.codemirror
 *
 * @copyright   (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

// No direct access
defined('_JEXEC') or die;

$params     = $displayData->params;
$fontFamily = isset($displayData->fontFamily) ?
$displayData->fontFamily : 'monospace';
$fontSize   = $params->get('fontSize', 13) . 'px;';
$lineHeight = $params->get('lineHeight', 1.2) .
'em;';

// Set the active line color.
$color           = $params->get('activeLineColor',
'#a4c2eb');
$r               = hexdec($color[1] . $color[2]);
$g               = hexdec($color[3] . $color[4]);
$b               = hexdec($color[5] . $color[6]);
$activeLineColor = 'rgba(' . $r . ', ' . $g . ',
' . $b . ', .5)';

// Set the color for matched tags.
$color               = $params->get('highlightMatchColor',
'#fa542f');
$r                   = hexdec($color[1] . $color[2]);
$g                   = hexdec($color[3] . $color[4]);
$b                   = hexdec($color[5] . $color[6]);
$highlightMatchColor = 'rgba(' . $r . ', ' . $g .
', ' . $b . ', .5)';

JFactory::getDocument()->addStyleDeclaration(
<<<CSS
		.CodeMirror
		{
			font-family: $fontFamily;
			font-size: $fontSize;
			line-height: $lineHeight;
			border: 1px solid #ccc;
		}
		/* In order to hid the Joomla menu */
		.CodeMirror-fullscreen
		{
			z-index: 1040;
		}
		/* Make the fold marker a little more visible/nice */
		.CodeMirror-foldmarker
		{
			background: rgb(255, 128, 0);
			background: rgba(255, 128, 0, .5);
			box-shadow: inset 0 0 2px rgba(255, 255, 255, .5);
			font-family: serif;
			font-size: 90%;
			border-radius: 1em;
			padding: 0 1em;
			vertical-align: middle;
			color: white;
			text-shadow: none;
		}
		.CodeMirror-foldgutter, .CodeMirror-markergutter { width: 1.2em;
text-align: center; }
		.CodeMirror-markergutter { cursor: pointer; }
		.CodeMirror-markergutter-mark { cursor: pointer; text-align: center; }
		.CodeMirror-markergutter-mark:after { content: "\25CF"; }
		.CodeMirror-activeline-background { background: $activeLineColor; }
		.CodeMirror-matchingtag { background: $highlightMatchColor; }
		.cm-matchhighlight {background-color: $highlightMatchColor; }
		.CodeMirror-selection-highlight-scrollbar {background-color:
$highlightMatchColor; }
CSS
);
editors/none/none.php000064400000007565147357022240010647 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.none
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Plain Textarea Editor Plugin
 *
 * @since  1.5
 */
class PlgEditorNone extends JPlugin
{
	/**
	 * Method to handle the onInitEditor event.
	 *  - Initialises the Editor
	 *
	 * @return  void
	 *
	 * @since 1.5
	 */
	public function onInit()
	{
		JHtml::_('script', 'editors/none/none.min.js',
array('version' => 'auto', 'relative'
=> true));
	}

	/**
	 * Copy editor content to form field.
	 *
	 * Not applicable in this editor.
	 *
	 * @param   string  $editor  the editor id
	 *
	 * @return  void
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSave($editor)
	{
	}

	/**
	 * Get the editor content.
	 *
	 * @param   string  $id  The id of the editor field.
	 *
	 * @return  string
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onGetContent($id)
	{
		return 'Joomla.editors.instances[' . json_encode($id) .
'].getValue();';
	}

	/**
	 * Set the editor content.
	 *
	 * @param   string  $id    The id of the editor field.
	 * @param   string  $html  The content to set.
	 *
	 * @return  string
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSetContent($id, $html)
	{
		return 'Joomla.editors.instances[' . json_encode($id) .
'].setValue(' . json_encode($html) . ');';
	}

	/**
	 * Inserts html code into the editor
	 *
	 * @param   string  $id  The id of the editor field
	 *
	 * @return  void
	 *
	 * @deprecated 4.0
	 */
	public function onGetInsertMethod($id)
	{
	}

	/**
	 * Display the editor area.
	 *
	 * @param   string   $name     The control name.
	 * @param   string   $content  The contents of the text area.
	 * @param   string   $width    The width of the text area (px or %).
	 * @param   string   $height   The height of the text area (px or %).
	 * @param   integer  $col      The number of columns for the textarea.
	 * @param   integer  $row      The number of rows for the textarea.
	 * @param   boolean  $buttons  True and the editor buttons will be
displayed.
	 * @param   string   $id       An optional ID for the textarea (note:
since 1.6). If not supplied the name is used.
	 * @param   string   $asset    The object asset
	 * @param   object   $author   The author.
	 * @param   array    $params   Associative array of editor parameters.
	 *
	 * @return  string
	 */
	public function onDisplay($name, $content, $width, $height, $col, $row,
$buttons = true,
		$id = null, $asset = null, $author = null, $params = array())
	{
		if (empty($id))
		{
			$id = $name;
		}

		// Only add "px" to width and height if they are not given as a
percentage
		if (is_numeric($width))
		{
			$width .= 'px';
		}

		if (is_numeric($height))
		{
			$height .= 'px';
		}

		$readonly = !empty($params['readonly']) ? ' readonly
disabled' : '';

		$editor = '<div class="js-editor-none">'
			. '<textarea name="' . $name . '"
id="' . $id . '" cols="' . $col .
'" rows="' . $row
			. '" style="width: ' . $width . '; height:
' . $height . ';"' . $readonly . '>' .
$content . '</textarea>'
			. $this->_displayButtons($id, $buttons, $asset, $author)
			. '</div>';

		return $editor;
	}

	/**
	 * Displays the editor buttons.
	 *
	 * @param   string  $name     The control name.
	 * @param   mixed   $buttons  [array with button objects | boolean true to
display buttons]
	 * @param   string  $asset    The object asset
	 * @param   object  $author   The author.
	 *
	 * @return  void|string HTML
	 */
	public function _displayButtons($name, $buttons, $asset, $author)
	{
		if (is_array($buttons) || (is_bool($buttons) && $buttons))
		{
			$buttons = $this->_subject->getButtons($name, $buttons, $asset,
$author);

			return JLayoutHelper::render('joomla.editors.buttons',
$buttons);
		}
	}
}
editors/none/none.xml000064400000001370147357022240010644 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="editors" method="upgrade">
	<name>plg_editors_none</name>
	<version>3.0.0</version>
	<creationDate>September 2005</creationDate>
	<author>Joomla! Project</author>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<description>PLG_NONE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="none">none.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors_none.ini</language>
		<language
tag="en-GB">en-GB.plg_editors_none.sys.ini</language>
	</languages>
</extension>
editors/tinymce/field/skins.php000064400000002740147357022240012621
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   (C) 2014 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

jimport('joomla.form.helper');

JFormHelper::loadFieldClass('list');

/**
 * Generates the list of options for available skins.
 *
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 * @since       3.4
 */
class JFormFieldSkins extends JFormFieldList
{
	protected $type = 'skins';

	/**
	 * Method to get the skins options.
	 *
	 * @return  array  The skins option objects.
	 *
	 * @since   3.4
	 */
	public function getOptions()
	{
		$options = array();

		$directories = glob(JPATH_ROOT . '/media/editors/tinymce/skins'
. '/*', GLOB_ONLYDIR);

		for ($i = 0, $iMax = count($directories); $i < $iMax; ++$i)
		{
			$dir = basename($directories[$i]);
			$options[] = JHtml::_('select.option', $i, $dir);
		}

		$options = array_merge(parent::getOptions(), $options);

		return $options;
	}

	/**
	 * Method to get the field input markup for the list of skins.
	 *
	 * @return  string  The field input markup.
	 *
	 * @since   3.4
	 */
	protected function getInput()
	{
		$html = array();

		// Get the field options.
		$options = (array) $this->getOptions();

		// Create a regular list.
		$html[] = JHtml::_('select.genericlist', $options,
$this->name, '', 'value', 'text',
$this->value, $this->id);

		return implode($html);
	}
}
editors/tinymce/field/tinymcebuilder.php000064400000017334147357022240014516
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   string  $autocomplete   Autocomplete attribute for the field.
 * @var   boolean $autofocus      Is autofocus enabled?
 * @var   string  $class          Classes for the input.
 * @var   string  $description    Description of the field.
 * @var   boolean $disabled       Is this field disabled?
 * @var   string  $group          Group the field belongs to.
<fields> section in form XML.
 * @var   boolean $hidden         Is this field hidden in the form?
 * @var   string  $hint           Placeholder for the field.
 * @var   string  $id             DOM id of the field.
 * @var   string  $label          Label of the field.
 * @var   string  $labelclass     Classes to apply to the label.
 * @var   boolean $multiple       Does this field support multiple values?
 * @var   string  $name           Name of the input field.
 * @var   string  $onchange       Onchange attribute for the field.
 * @var   string  $onclick        Onclick attribute for the field.
 * @var   string  $pattern        Pattern (Reg Ex) of value of the form
field.
 * @var   boolean $readonly       Is this field read only?
 * @var   boolean $repeat         Allows extensions to duplicate elements.
 * @var   boolean $required       Is this field required?
 * @var   integer $size           Size attribute of the input.
 * @var   boolean $spellcheck     Spellcheck state for the form field.
 * @var   string  $validate       Validation rules to apply.
 * @var   array   $value          Value of the field.
  *
 * @var   array   $menus           List of the menu items
 * @var   array   $menubarSource   Menu items for builder
 * @var   array   $buttons         List of the buttons
 * @var   array   $buttonsSource   Buttons by group, for the builder
 * @var   array   $toolbarPreset   Toolbar preset (default values)
 * @var   int     $setsAmount      Amount of sets
 * @var   array   $setsNames       List of Sets names
 * @var   JForm[] $setsForms       Form with extra options for an each set
 * @var   string   $languageFile   TinyMCE language file to translate the
buttons
 *
 * @var   JLayoutFile  $this       Context
 */

JHtml::_('behavior.core');
JHtml::_('stylesheet',
'media/editors/tinymce/skins/lightgray/skin.min.css',
array('version' => 'auto', 'relative'
=> false));
JHtml::_('jquery.ui', array('core',
'sortable'));
JHtml::_('script',
'editors/tinymce/tinymce-builder.js', array('version'
=> 'auto', 'relative' => true));

if ($languageFile)
{
	JHtml::_('script', $languageFile, array('version'
=> 'auto', 'relative' => false));
}


$doc = JFactory::getDocument();
$doc->addScriptOptions('plg_editors_tinymce_builder', array(
		'menus'         => $menus,
		'buttons'       => $buttons,
		'toolbarPreset' => $toolbarPreset,
		'formControl'   => $name . '[toolbars]',
	)
);
$doc->addStyleDeclaration('
    #joomla-tinymce-builder{
		margin-left: -180px;
	}
	.mce-menubar,
	.mce-panel {
		min-height: 18px;
		border-bottom: 1px solid rgba(217,217,217,0.52);
		white-space: normal;
	}
	.mce-tinymce {
		margin-bottom: 20px;
	}
	.mce-panel .drop-area-highlight{
		background-color: #d0d0d0;
	}
	.mce-panel .mce-btn.ui-state-highlight{
		height: 28px;
		width: 40px;
		background-color: #409740;
		border: 1px solid #f0f0f0;
	}
	.timymce-builder-toolbar .mce-btn.ui-state-highlight{
		height: 22px;
		width: 28px;
	}
');

?>
<div id="joomla-tinymce-builder">

	<p><?php echo
JText::_('PLG_TINY_SET_SOURCE_PANEL_DESCRIPTION');
?></p>

	<div class="mce-tinymce mce-container mce-panel">
		<div class="mce-container-body mce-stack-layout">

			<div class="mce-container mce-menubar mce-toolbar
mce-stack-layout-item">
				<div class="mce-container-body mce-flow-layout
timymce-builder-menu source" data-group="menu"
					data-value="<?php echo
$this->escape(json_encode($menubarSource)); ?>">
				</div>
			</div>

			<div class="mce-toolbar-grp mce-container mce-panel
mce-stack-layout-item">
				<div class="mce-container-body mce-flow-layout
timymce-builder-toolbar source" data-group="toolbar"
					data-value="<?php echo
$this->escape(json_encode($buttonsSource)); ?>">
				</div>
			</div>
		</div>
	</div>

	<hr />
	<p><?php echo
JText::_('PLG_TINY_SET_TARGET_PANEL_DESCRIPTION');
?></p>

	<!-- Render tabs for each set -->
	<ul class="nav nav-tabs" id="set-tabs">
		<?php foreach ( $setsNames as $num => $title ) : ?>
		<li class="<?php echo $num === $setsAmount - 1 ?
'active' : ''; ?>">
			<a href="#set-<?php echo $num; ?>"><?php echo
$title; ?></a>
		</li>
		<?php endforeach; ?>
	</ul>

	<!-- Render tab content for each set -->
	<div class="tab-content">
		<?php
		$presetButtonClases = array(
			'simple'   => 'btn-success',
			'medium'   => 'btn-info',
			'advanced' => 'btn-warning',
		);
		foreach ( $setsNames as $num => $title ) :

			// Check whether the values exists, and if empty then use from preset
			if (empty($value['toolbars'][$num]['menu'])
				&&
empty($value['toolbars'][$num]['toolbar1'])
				&&
empty($value['toolbars'][$num]['toolbar2']))
			{
				// Take the preset for default value
				switch ($num) {
					case 0:
						$preset = $toolbarPreset['advanced'];
						break;
					case 1:
						$preset = $toolbarPreset['medium'];
						break;
					default:
						$preset = $toolbarPreset['simple'];
				}

				$value['toolbars'][$num] = $preset;
			}

			// Take existing values
			$valMenu = empty($value['toolbars'][$num]['menu'])  
  ? array() : $value['toolbars'][$num]['menu'];
			$valBar1 =
empty($value['toolbars'][$num]['toolbar1']) ? array() :
$value['toolbars'][$num]['toolbar1'];
			$valBar2 =
empty($value['toolbars'][$num]['toolbar2']) ? array() :
$value['toolbars'][$num]['toolbar2'];
		?>
			<div class="tab-pane <?php echo $num === $setsAmount - 1 ?
'active' : ''; ?>" id="set-<?php echo
$num; ?>">
				<div class="btn-toolbar clearfix">
					<div class="btn-group pull-right">

					<?php foreach(array_keys($toolbarPreset) as $presetName) :
						$btnClass = empty($presetButtonClases[$presetName]) ?
'btn-primary' : $presetButtonClases[$presetName];
						?>
						<button type="button" class="btn btn-mini <?php
echo $btnClass; ?> button-action"
						    data-action="setPreset" data-preset="<?php echo
$presetName; ?>" data-set="<?php echo $num; ?>">
							<?php echo JText::_('PLG_TINY_SET_PRESET_BUTTON_' .
$presetName); ?>
						</button>
					<?php endforeach; ?>

						<button type="button" class="btn btn-mini
btn-danger button-action"
						     data-action="clearPane" data-set="<?php echo
$num; ?>">
							<?php echo JText::_('JCLEAR'); ?></button>
					</div>
				</div>

				<div class="mce-tinymce mce-container mce-panel">
					<div class="mce-container-body mce-stack-layout">
						<div class="mce-container mce-menubar mce-toolbar
timymce-builder-menu target"
							data-group="menu" data-set="<?php echo $num;
?>"
							data-value="<?php echo
$this->escape(json_encode($valMenu)); ?>">
						</div>
						<div class="mce-toolbar-grp mce-container mce-panel
timymce-builder-toolbar target"
						    data-group="toolbar1" data-set="<?php echo
$num; ?>"
						    data-value="<?php echo
$this->escape(json_encode($valBar1)); ?>">
						</div>
						<div class="mce-toolbar-grp mce-container mce-panel
timymce-builder-toolbar target"
						    data-group="toolbar2" data-set="<?php echo
$num; ?>"
						    data-value="<?php echo
$this->escape(json_encode($valBar2)); ?>">
						</div>
					</div>
				</div>

				<!-- Render the form for extra options -->
				<?php echo $this->sublayout('setoptions',
array('form' => $setsForms[$num])); ?>
			</div>
		<?php endforeach; ?>
	</div>
</div>
editors/tinymce/field/uploaddirs.php000064400000004550147357022240013641
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

jimport('joomla.form.helper');

JFormHelper::loadFieldClass('folderlist');

/**
 * Generates the list of directories  available for drag and drop upload.
 *
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 * @since       3.7.0
 */
class JFormFieldUploaddirs extends JFormFieldFolderList
{
	protected $type = 'uploaddirs';

	/**
	 * Method to attach a JForm object to the field.
	 *
	 * @param   SimpleXMLElement  $element  The SimpleXMLElement object
representing the `<field>` tag for the form field object.
	 * @param   mixed             $value    The form field value to validate.
	 * @param   string            $group    The field name group control
value. This acts as an array container for the field.
	 *                                      For example if the field has
name="foo" and the group value is set to "bar" then the
	 *                                      full field name would end up being
"bar[foo]".
	 *
	 * @return  boolean  True on success.
	 *
	 * @see     JFormField::setup()
	 * @since   3.7.0
	 */
	public function setup(SimpleXMLElement $element, $value, $group = null)
	{
		$return = parent::setup($element, $value, $group);

		// Get the path in which to search for file options.
		$this->directory   =
JComponentHelper::getParams('com_media')->get('image_path');
		$this->recursive   = true;
		$this->hideDefault = true;

		return $return;
	}

	/**
	 * Method to get the directories options.
	 *
	 * @return  array  The dirs option objects.
	 *
	 * @since   3.7.0
	 */
	public function getOptions()
	{
		return parent::getOptions();
	}

	/**
	 * Method to get the field input markup for the list of directories.
	 *
	 * @return  string  The field input markup.
	 *
	 * @since   3.7.0
	 */
	protected function getInput()
	{
		$html = array();

		// Get the field options.
		$options = (array) $this->getOptions();

		// Reset the non selected value to null
		if ($options[0]->value === '-1')
		{
			$options[0]->value = '';
		}

		// Create a regular list.
		$html[] = JHtml::_('select.genericlist', $options,
$this->name, '', 'value', 'text',
$this->value, $this->id);

		return implode($html);
	}
}
editors/tinymce/form/setoptions.xml000064400000017641147357022240013600
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
    <field
        name="access"
        type="usergrouplist"
        label="PLG_TINY_FIELD_SETACCESS_LABEL"
        description="PLG_TINY_FIELD_SETACCESS_DESC"
        multiple="true"
        class="access-select"
        labelclass="label label-success"
    />

    <field
        name="skins"
        type="note"
        label="PLG_TINY_FIELD_SKIN_INFO_LABEL"
        description="PLG_TINY_FIELD_SKIN_INFO_DESC"
    />

    <field
        name="skin"
        type="skins"
        label="PLG_TINY_FIELD_SKIN_LABEL"
        description="PLG_TINY_FIELD_SKIN_DESC"
    />

    <field
        name="skin_admin"
        type="skins"
        label="PLG_TINY_FIELD_SKIN_ADMIN_LABEL"
        description="PLG_TINY_FIELD_SKIN_ADMIN_DESC"
    />

    <field
        name="mobile"
        type="radio"
        label="PLG_TINY_FIELD_MOBILE_LABEL"
        description="PLG_TINY_FIELD_MOBILE_DESC"
        class="btn-group btn-group-yesno"
        default="0"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="drag_drop"
        type="radio"
        label="PLG_TINY_FIELD_DRAG_DROP_LABEL"
        description="PLG_TINY_FIELD_DRAG_DROP_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="path"
        type="uploaddirs"
        label="PLG_TINY_FIELD_CUSTOM_PATH_LABEL"
        description="PLG_TINY_FIELD_CUSTOM_PATH_DESC"
        class="input-xxlarge"
        showon="drag_drop:1"
    />

    <field
        name="entity_encoding"
        type="list"
        label="PLG_TINY_FIELD_ENCODING_LABEL"
        description="PLG_TINY_FIELD_ENCODING_DESC"
        default="raw"
        >
        <option
value="named">PLG_TINY_FIELD_VALUE_NAMED</option>
        <option
value="numeric">PLG_TINY_FIELD_VALUE_NUMERIC</option>
        <option
value="raw">PLG_TINY_FIELD_VALUE_RAW</option>
    </field>

    <field
        name="lang_mode"
        type="radio"
        label="PLG_TINY_FIELD_LANGSELECT_LABEL"
        description="PLG_TINY_FIELD_LANGSELECT_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="lang_code"
        type="filelist"
        label="PLG_TINY_FIELD_LANGCODE_LABEL"
        description="PLG_TINY_FIELD_LANGCODE_DESC"
        class="inputbox"
        stripext="1"
        directory="media/editors/tinymce/langs/"
        hide_none="1"
        default="en"
        hide_default="1"
        filter="\.js$"
        size="10"
        showon="lang_mode:0"
    />

    <field
        name="text_direction"
        type="list"
        label="PLG_TINY_FIELD_DIRECTION_LABEL"
        description="PLG_TINY_FIELD_DIRECTION_DESC"
        default="ltr"
        >
        <option
value="ltr">PLG_TINY_FIELD_VALUE_LTR</option>
        <option
value="rtl">PLG_TINY_FIELD_VALUE_RTL</option>
    </field>

    <field
        name="content_css"
        type="radio"
        label="PLG_TINY_FIELD_CSS_LABEL"
        description="PLG_TINY_FIELD_CSS_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="content_css_custom"
        type="text"
        label="PLG_TINY_FIELD_CUSTOM_CSS_LABEL"
        description="PLG_TINY_FIELD_CUSTOM_CSS_DESC"
        class="input-xxlarge"
    />

    <field
        name="relative_urls"
        type="list"
        label="PLG_TINY_FIELD_URLS_LABEL"
        description="PLG_TINY_FIELD_URLS_DESC"
        default="1"
        >
        <option
value="0">PLG_TINY_FIELD_VALUE_ABSOLUTE</option>
        <option
value="1">PLG_TINY_FIELD_VALUE_RELATIVE</option>
    </field>

    <field
        name="newlines"
        type="list"
        label="PLG_TINY_FIELD_NEWLINES_LABEL"
        description="PLG_TINY_FIELD_NEWLINES_DESC"
        default="0"
        >
        <option
value="1">PLG_TINY_FIELD_VALUE_BR</option>
        <option
value="0">PLG_TINY_FIELD_VALUE_P</option>
    </field>

    <field
        name="use_config_textfilters"
        type="radio"
        label="PLG_TINY_CONFIG_TEXTFILTER_ACL_LABEL"
        description="PLG_TINY_CONFIG_TEXTFILTER_ACL_DESC"
        class="btn-group btn-group-yesno"
        default="0"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="invalid_elements"
        type="text"
        label="PLG_TINY_FIELD_PROHIBITED_LABEL"
        description="PLG_TINY_FIELD_PROHIBITED_DESC"
        showon="use_config_textfilters:0"
        default="script,applet,iframe"
        class="input-xxlarge"
    />

    <field
        name="valid_elements"
        type="text"
        label="PLG_TINY_FIELD_VALIDELEMENTS_LABEL"
        description="PLG_TINY_FIELD_VALIDELEMENTS_DESC"
        showon="use_config_textfilters:0"
        class="input-xxlarge"
    />

    <field
        name="extended_elements"
        type="text"
        label="PLG_TINY_FIELD_ELEMENTS_LABEL"
        description="PLG_TINY_FIELD_ELEMENTS_DESC"
        showon="use_config_textfilters:0"
        class="input-xxlarge"
    />

    <!-- Extra plugins -->
    <field
        name="resizing"
        type="radio"
        label="PLG_TINY_FIELD_RESIZING_LABEL"
        description="PLG_TINY_FIELD_RESIZING_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="resize_horizontal"
        type="radio"
        label="PLG_TINY_FIELD_RESIZE_HORIZONTAL_LABEL"
        description="PLG_TINY_FIELD_RESIZE_HORIZONTAL_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        showon="resizing:1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="element_path"
        type="radio"
        label="PLG_TINY_FIELD_PATH_LABEL"
        description="PLG_TINY_FIELD_PATH_DESC"
        class="btn-group btn-group-yesno"
        default="0"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="wordcount"
        type="radio"
        label="PLG_TINY_FIELD_WORDCOUNT_LABEL"
        description="PLG_TINY_FIELD_WORDCOUNT_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="image_advtab"
        type="radio"
        label="PLG_TINY_FIELD_ADVIMAGE_LABEL"
        description="PLG_TINY_FIELD_ADVIMAGE_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="advlist"
        type="radio"
        label="PLG_TINY_FIELD_ADVLIST_LABEL"
        description="PLG_TINY_FIELD_ADVLIST_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="contextmenu"
        type="radio"
        label="PLG_TINY_FIELD_CONTEXTMENU_LABEL"
        description="PLG_TINY_FIELD_CONTEXTMENU_DESC"
        class="btn-group btn-group-yesno"
        default="1"
        >
        <option value="1">JON</option>
        <option value="0">JOFF</option>
    </field>

    <field
        name="custom_plugin"
        type="text"
        label="PLG_TINY_FIELD_CUSTOMPLUGIN_LABEL"
        description="PLG_TINY_FIELD_CUSTOMPLUGIN_DESC"
        class="input-xxlarge"
    />

    <field
        name="custom_button"
        type="text"
        label="PLG_TINY_FIELD_CUSTOMBUTTON_LABEL"
        description="PLG_TINY_FIELD_CUSTOMBUTTON_DESC"
        class="input-xxlarge"
    />
</form>editors/tinymce/tinymce.php000064400000163176147357022240012072
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\HTML\HTMLHelper;

/**
 * TinyMCE Editor Plugin
 *
 * @since  1.5
 */
class PlgEditorTinymce extends JPlugin
{
	/**
	 * Base path for editor files
	 *
	 * @since  3.5
	 */
	protected $_basePath = 'media/editors/tinymce';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Loads the application object
	 *
	 * @var    JApplicationCms
	 * @since  3.2
	 */
	protected $app = null;

	/**
	 * Initialises the Editor.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onInit()
	{
		JHtml::_('behavior.core');
		JHtml::_('behavior.polyfill', array('event'),
'lt IE 9');
		JHtml::_('script', $this->_basePath .
'/tinymce.min.js', array('version' =>
'auto'));
		JHtml::_('script', 'editors/tinymce/tinymce.min.js',
array('version' => 'auto', 'relative'
=> true));
	}

	/**
	 * TinyMCE WYSIWYG Editor - get the editor content
	 *
	 * @param   string  $id  The name of the editor
	 *
	 * @since   1.5
	 *
	 * @return  string
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onGetContent($id)
	{
		return 'Joomla.editors.instances[' . json_encode($id) .
'].getValue();';
	}

	/**
	 * TinyMCE WYSIWYG Editor - set the editor content
	 *
	 * @param   string  $id    The name of the editor
	 * @param   string  $html  The html to place in the editor
	 *
	 * @since   1.5
	 *
	 * @return  string
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSetContent($id, $html)
	{
		return 'Joomla.editors.instances[' . json_encode($id) .
'].setValue(' . json_encode($html) . ');';
	}

	/**
	 * TinyMCE WYSIWYG Editor - copy editor content to form field
	 *
	 * @param   string  $id  The name of the editor
	 *
	 * @since   1.5
	 *
	 * @return  void
	 *
	 * @deprecated 4.0 Use directly the returned code
	 */
	public function onSave($id)
	{
	}

	/**
	 * Inserts html code into the editor
	 *
	 * @param   string  $name  The name of the editor
	 *
	 * @since   1.5
	 *
	 * @return  string
	 *
	 * @deprecated 3.5 tinyMCE (API v4) will get the content automatically
from the text area
	 */
	public function onGetInsertMethod($name)
	{
	}

	/**
	 * Display the editor area.
	 *
	 * @param   string   $name     The name of the editor area.
	 * @param   string   $content  The content of the field.
	 * @param   string   $width    The width of the editor area.
	 * @param   string   $height   The height of the editor area.
	 * @param   int      $col      The number of columns for the editor area.
	 * @param   int      $row      The number of rows for the editor area.
	 * @param   boolean  $buttons  True and the editor buttons will be
displayed.
	 * @param   string   $id       An optional ID for the textarea. If not
supplied the name is used.
	 * @param   string   $asset    The object asset
	 * @param   object   $author   The author.
	 * @param   array    $params   Associative array of editor parameters.
	 *
	 * @return  string
	 */
	public function onDisplay(
		$name, $content, $width, $height, $col, $row, $buttons = true, $id =
null, $asset = null, $author = null, $params = array())
	{
		$app = JFactory::getApplication();

		// Check for old params for B/C
		$config_warn_count =
$app->getUserState('plg_editors_tinymce.config_legacy_warn_count',
0);

		if ($this->params->exists('mode') &&
$this->params->exists('alignment'))
		{
			if ($app->isClient('administrator') &&
$config_warn_count < 2)
			{
				$link =
JRoute::_('index.php?option=com_plugins&task=plugin.edit&extension_id='
. $this->getPluginId());
				$app->enqueueMessage(JText::sprintf('PLG_TINY_LEGACY_WARNING',
$link), 'warning');
				$app->setUserState('plg_editors_tinymce.config_legacy_warn_count',
++$config_warn_count);
			}

			return $this->onDisplayLegacy($name, $content, $width, $height, $col,
$row, $buttons, $id, $asset, $author, $params);
		}

		if (empty($id))
		{
			$id = $name;
		}

		$id            = preg_replace('/(\s|[^A-Za-z0-9_])+/',
'_', $id);
		$nameGroup     = explode('[',
preg_replace('/\[\]|\]/', '', $name));
		$fieldName     = end($nameGroup);
		$scriptOptions = array();

		// Check for existing options
		$doc     = JFactory::getDocument();
		$options = $doc->getScriptOptions('plg_editor_tinymce');

		// Only add "px" to width and height if they are not given as a
percentage
		if (is_numeric($width))
		{
			$width .= 'px';
		}

		if (is_numeric($height))
		{
			$height .= 'px';
		}

		// Data object for the layout
		$textarea = new stdClass;
		$textarea->name    = $name;
		$textarea->id      = $id;
		$textarea->class   = 'mce_editable joomla-editor-tinymce';
		$textarea->cols    = $col;
		$textarea->rows    = $row;
		$textarea->width   = $width;
		$textarea->height  = $height;
		$textarea->content = $content;

		// Set editor to readonly mode
		$textarea->readonly = !empty($params['readonly']);

		// Render Editor markup
		$editor = '<div class="js-editor-tinymce">';
		$editor .= JLayoutHelper::render('joomla.tinymce.textarea',
$textarea);
		$editor .= $this->_toogleButton($id);
		$editor .= '</div>';

		// Prepare the instance specific options, actually the ext-buttons
		if
(empty($options['tinyMCE'][$fieldName]['joomlaExtButtons']))
		{
			$btns = $this->tinyButtons($id, $buttons);

			if (!empty($btns['names']))
			{
				JHtml::_('script',
'editors/tinymce/tiny-close.min.js', array('version'
=> 'auto', 'relative' => true),
array('defer' => 'defer'));
			}

			// Set editor to readonly mode
			if (!empty($params['readonly']))
			{
				$options['tinyMCE'][$fieldName]['readonly'] = 1;
			}

			$options['tinyMCE'][$fieldName]['joomlaMergeDefaults']
= true;
			$options['tinyMCE'][$fieldName]['joomlaExtButtons'] 
  = $btns;

			$doc->addScriptOptions('plg_editor_tinymce', $options,
false);
		}

		// Setup Default (common) options for the Editor script

		// Check whether we already have them
		if (!empty($options['tinyMCE']['default']))
		{
			return $editor;
		}

		$user     = JFactory::getUser();
		$language = JFactory::getLanguage();
		$theme    = 'modern';
		$ugroups  = array_combine($user->getAuthorisedGroups(),
$user->getAuthorisedGroups());

		// Prepare the parameters
		$levelParams      = new Joomla\Registry\Registry;
		$extraOptions     = new stdClass;
		$toolbarParams    = new stdClass;
		$extraOptionsAll  =
$this->params->get('configuration.setoptions', array());
		$toolbarParamsAll =
$this->params->get('configuration.toolbars', array());

		// Get configuration depend from User group
		foreach ($extraOptionsAll as $set => $val)
		{
			$val->access = empty($val->access) ? array() : $val->access;

			// Check whether User in one of allowed group
			foreach ($val->access as $group)
			{
				if (isset($ugroups[$group]))
				{
					$extraOptions  = $val;
					$toolbarParams = $toolbarParamsAll->$set;
				}
			}
		}

		// Merge the params
		$levelParams->loadObject($toolbarParams);
		$levelParams->loadObject($extraOptions);

		// List the skins
		$skindirs = glob(JPATH_ROOT . '/media/editors/tinymce/skins' .
'/*', GLOB_ONLYDIR);

		// Set the selected skin
		$skin = 'lightgray';
		$side = $app->isClient('administrator') ?
'skin_admin' : 'skin';

		if ((int) $levelParams->get($side, 0) < count($skindirs))
		{
			$skin = basename($skindirs[(int) $levelParams->get($side, 0)]);
		}

		$langMode   = $levelParams->get('lang_mode', 1);
		$langPrefix = $levelParams->get('lang_code',
'en');

		if ($langMode)
		{
			if (file_exists(JPATH_ROOT . '/media/editors/tinymce/langs/' .
$language->getTag() . '.js'))
			{
				$langPrefix = $language->getTag();
			}
			elseif (file_exists(JPATH_ROOT .
'/media/editors/tinymce/langs/' . substr($language->getTag(),
0, strpos($language->getTag(), '-')) . '.js'))
			{
				$langPrefix = substr($language->getTag(), 0,
strpos($language->getTag(), '-'));
			}
			else
			{
				$langPrefix = 'en';
			}
		}

		$text_direction = 'ltr';

		if ($language->isRtl())
		{
			$text_direction = 'rtl';
		}

		$use_content_css    = $levelParams->get('content_css', 1);
		$content_css_custom =
$levelParams->get('content_css_custom', '');

		/*
		 * Lets get the default template for the site application
		 */
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
			->select('template')
			->from('#__template_styles')
			->where('client_id=0 AND home=' .
$db->quote('1'));

		$db->setQuery($query);

		try
		{
			$template = $db->loadResult();
		}
		catch (RuntimeException $e)
		{
			$app->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'),
'error');

			return '';
		}

		$content_css    = null;
		$templates_path = JPATH_SITE . '/templates';

		// Loading of css file for 'styles' dropdown
		if ($content_css_custom)
		{
			// If URL, just pass it to $content_css
			if (strpos($content_css_custom, 'http') !== false)
			{
				$content_css = $content_css_custom;
			}

			// If it is not a URL, assume it is a file name in the current template
folder
			else
			{
				$content_css = JUri::root(true) . '/templates/' . $template .
'/css/' . $content_css_custom;

				// Issue warning notice if the file is not found (but pass name to
$content_css anyway to avoid TinyMCE error
				if (!file_exists($templates_path . '/' . $template .
'/css/' . $content_css_custom))
				{
					$msg =
sprintf(JText::_('PLG_TINY_ERR_CUSTOMCSSFILENOTPRESENT'),
$content_css_custom);
					JLog::add($msg, JLog::WARNING, 'jerror');
				}
			}
		}
		else
		{
			// Process when use_content_css is Yes and no custom file given
			if ($use_content_css)
			{
				// First check templates folder for default template
				// if no editor.css file in templates folder, check system template
folder
				if (!file_exists($templates_path . '/' . $template .
'/css/editor.css'))
				{
					// If no editor.css file in system folder, show alert
					if (!file_exists($templates_path .
'/system/css/editor.css'))
					{
						JLog::add(JText::_('PLG_TINY_ERR_EDITORCSSFILENOTPRESENT'),
JLog::WARNING, 'jerror');
					}
					else
					{
						$content_css = JUri::root(true) .
'/templates/system/css/editor.css';
					}
				}
				else
				{
					$content_css = JUri::root(true) . '/templates/' . $template
. '/css/editor.css';
				}
			}
		}

		$ignore_filter = false;

		// Text filtering
		if ($levelParams->get('use_config_textfilters', 0))
		{
			// Use filters from com_config
			$filter = static::getGlobalFilters();

			$ignore_filter = $filter === false;

			$tagBlacklist  = !empty($filter->tagBlacklist) ?
$filter->tagBlacklist : array();
			$attrBlacklist = !empty($filter->attrBlacklist) ?
$filter->attrBlacklist : array();
			$tagArray      = !empty($filter->tagArray) ? $filter->tagArray :
array();
			$attrArray     = !empty($filter->attrArray) ? $filter->attrArray :
array();

			$invalid_elements  = implode(',', array_merge($tagBlacklist,
$attrBlacklist, $tagArray, $attrArray));

			// Valid elements are all whitelist entries in com_config, which are now
missing in the tagBlacklist
			$default_filter = JFilterInput::getInstance();
			$valid_elements = implode(',',
array_diff($default_filter->tagBlacklist, $tagBlacklist));

			$extended_elements = '';
		}
		else
		{
			// Use filters from TinyMCE params
			$invalid_elements  =
trim($levelParams->get('invalid_elements',
'script,applet,iframe'));
			$extended_elements =
trim($levelParams->get('extended_elements', ''));
			$valid_elements    =
trim($levelParams->get('valid_elements', ''));
		}

		$html_height = $this->params->get('html_height',
'550');
		$html_width  = $this->params->get('html_width',
'');

		if ($html_width == 750)
		{
			$html_width = '';
		}

		// The param is true for vertical resizing only, false or both
		$resizing          = (bool) $levelParams->get('resizing',
true);
		$resize_horizontal = (bool)
$levelParams->get('resize_horizontal', true);

		if ($resizing && $resize_horizontal)
		{
			$resizing = 'both';
		}

		// Set of always available plugins
		$plugins  = array(
			'autolink',
			'lists',
			'colorpicker',
			'importcss',
		);

		// Allowed elements
		$elements = array(
			'hr[id|title|alt|class|width|size|noshade]',
		);

		if ($extended_elements)
		{
			$elements = array_merge($elements, explode(',',
$extended_elements));
		}

		// Prepare the toolbar/menubar
		$knownButtons = static::getKnownButtons();

		// Check if there no value at all
		if (!$levelParams->get('menu') &&
!$levelParams->get('toolbar1') &&
!$levelParams->get('toolbar2'))
		{
			// Get from preset
			$presets = static::getToolbarPreset();

			/*
			 * Predefine group as:
			 * Set 0: for Administrator, Editor, Super Users (4,7,8)
			 * Set 1: for Registered, Manager (2,6), all else are public
			 */
			switch (true)
			{
				case isset($ugroups[4]) || isset($ugroups[7]) || isset($ugroups[8]):
					$preset = $presets['advanced'];
					break;

				case isset($ugroups[2]) || isset($ugroups[6]):
					$preset = $presets['medium'];
					break;

				default:
					$preset = $presets['simple'];
			}

			$levelParams->loadArray($preset);
		}

		$menubar  = (array) $levelParams->get('menu', array());
		$toolbar1 = (array) $levelParams->get('toolbar1', array());
		$toolbar2 = (array) $levelParams->get('toolbar2', array());

		// Make an easy way to check which button is enabled
		$allButtons = array_merge($toolbar1, $toolbar2);
		$allButtons = array_combine($allButtons, $allButtons);

		// Check for button-specific plugins
		foreach ($allButtons as $btnName)
		{
			if (!empty($knownButtons[$btnName]['plugin']))
			{
				$plugins[] = $knownButtons[$btnName]['plugin'];
			}
		}

		// Template
		$templates = array();

		if (!empty($allButtons['template']))
		{
			// Note this check for the template_list.js file will be removed in
Joomla 4.0
			if (is_file(JPATH_ROOT .
'/media/editors/tinymce/templates/template_list.js'))
			{
				// If using the legacy file we need to include and input the files the
new way
				$str = file_get_contents(JPATH_ROOT .
'/media/editors/tinymce/templates/template_list.js');

				// Find from one [ to the last ]
				$matches = array();
				preg_match_all('/\[.*\]/', $str, $matches);

				// Set variables
				foreach ($matches['0'] as $match)
				{
					$values = array();
					preg_match_all('/\".*\"/', $match, $values);
					$result       = trim($values['0']['0'],
'"');
					$final_result = explode(',', $result);

					$templates[] = array(
						'title' => trim($final_result['0'], '
" '),
						'description' => trim($final_result['2'],
' " '),
						'url' => JUri::root(true) . '/' .
trim($final_result['1'], ' " '),
					);
				}

			}
			else
			{
				foreach (glob(JPATH_ROOT .
'/media/editors/tinymce/templates/*.html') as $filename)
				{
					$filename = basename($filename, '.html');

					if ($filename !== 'index')
					{
						$lang        = JFactory::getLanguage();
						$title       = $filename;
						$description = ' ';

						if ($lang->hasKey('PLG_TINY_TEMPLATE_' .
strtoupper($filename) . '_TITLE'))
						{
							$title = JText::_('PLG_TINY_TEMPLATE_' .
strtoupper($filename) . '_TITLE');
						}

						if ($lang->hasKey('PLG_TINY_TEMPLATE_' .
strtoupper($filename) . '_DESC'))
						{
							$description = JText::_('PLG_TINY_TEMPLATE_' .
strtoupper($filename) . '_DESC');
						}

						$templates[] = array(
							'title' => $title,
							'description' => $description,
							'url' => JUri::root(true) .
'/media/editors/tinymce/templates/' . $filename .
'.html',
						);
					}
				}
			}
		}

		// Check for extra plugins, from the setoptions form
		foreach (array('wordcount' => 1, 'advlist' =>
1, 'autosave' => 1, 'contextmenu' => 1) as $pName
=> $def)
		{
			if ($levelParams->get($pName, $def))
			{
				$plugins[] = $pName;
			}
		}

		// User custom plugins and buttons
		$custom_plugin = trim($levelParams->get('custom_plugin',
''));
		$custom_button = trim($levelParams->get('custom_button',
''));

		if ($custom_plugin)
		{
			$separator = strpos($custom_plugin, ',') !== false ?
',' : ' ';
			$plugins   = array_merge($plugins, explode($separator, $custom_plugin));
		}

		if ($custom_button)
		{
			$separator = strpos($custom_button, ',') !== false ?
',' : ' ';
			$toolbar1  = array_merge($toolbar1, explode($separator,
$custom_button));
		}

		// Drag and drop Images
		$allowImgPaste = false;
		$dragdrop      = $levelParams->get('drag_drop', 1);

		if ($dragdrop && $user->authorise('core.create',
'com_media'))
		{
			$externalPlugins['jdragdrop'] = HTMLHelper::_(
					'script',
					'editors/tinymce/plugins/dragdrop/plugin.min.js',
					array('relative' => true, 'version' =>
'auto', 'pathOnly' => true)
				);
			$allowImgPaste = true;
			$isSubDir      = '';
			$session       = JFactory::getSession();
			$uploadUrl     = JUri::base() .
'index.php?option=com_media&task=file.upload&tmpl=component&'
				. $session->getName() . '=' . $session->getId()
				. '&' . JSession::getFormToken() . '=1'
				. '&asset=image&format=json';

			if ($app->isClient('site'))
			{
				$uploadUrl = htmlentities($uploadUrl, 0, 'UTF-8', false);
			}

			// Is Joomla installed in subdirectory
			if (JUri::root(true) !== '/')
			{
				$isSubDir = JUri::root(true);
			}

			JText::script('PLG_TINY_ERR_UNSUPPORTEDBROWSER');

			$scriptOptions['setCustomDir']    = $isSubDir;
			$scriptOptions['mediaUploadPath'] =
$levelParams->get('path', '');
			$scriptOptions['uploadUri']       = $uploadUrl;
		}

		// Build the final options set
		$scriptOptions = array_merge(
			$scriptOptions,
			array(
			'suffix'  => '.min',
			'baseURL' => JUri::root(true) .
'/media/editors/tinymce',
			'directionality' => $text_direction,
			'language' => $langPrefix,
			'autosave_restore_when_empty' => false,
			'skin'   => $skin,
			'theme'  => $theme,
			'schema' => 'html5',

			// Toolbars
			'menubar'  => empty($menubar)  ? false : implode('
', array_unique($menubar)),
			'toolbar1' => empty($toolbar1) ? null  : implode('
', $toolbar1),
			'toolbar2' => empty($toolbar2) ? null  : implode('
', $toolbar2),

			'plugins'  => implode(',',
array_unique($plugins)),

			// Cleanup/Output
			'inline_styles'    => true,
			'gecko_spellcheck' => true,
			'entity_encoding'  =>
$levelParams->get('entity_encoding', 'raw'),
			'verify_html'      => !$ignore_filter,

			'valid_elements'          => $valid_elements,
			'extended_valid_elements' => implode(',',
$elements),
			'invalid_elements'        => $invalid_elements,

			// URL
			'relative_urls'      => (bool)
$levelParams->get('relative_urls', true),
			'remove_script_host' => false,

			// Layout
			'content_css'        => $content_css,
			'document_base_url'  => JUri::root(true) . '/',
			'paste_data_images'  => $allowImgPaste,
			'importcss_append'   => true,
			'image_title'        => true,
			'height'             => $html_height,
			'width'              => $html_width,
			'resize'             => $resizing,
			'templates'          => $templates,
			'image_advtab'       => (bool)
$levelParams->get('image_advtab', false),
			'external_plugins'   => empty($externalPlugins) ? null  :
$externalPlugins,
			'contextmenu'        => (bool)
$levelParams->get('contextmenu', true) ? null : false,
			'elementpath'        => (bool)
$levelParams->get('element_path', true),
		)
		);

		if ($levelParams->get('newlines'))
		{
			// Break
			$scriptOptions['force_br_newlines'] = true;
			$scriptOptions['force_p_newlines']  = false;
			$scriptOptions['forced_root_block'] = '';
		}
		else
		{
			// Paragraph
			$scriptOptions['force_br_newlines'] = false;
			$scriptOptions['force_p_newlines']  = true;
			$scriptOptions['forced_root_block'] = 'p';
		}

		$scriptOptions['rel_list'] = array(
			array('title' => 'None', 'value' =>
''),
			array('title' => 'Alternate', 'value'
=> 'alternate'),
			array('title' => 'Author', 'value'
=> 'author'),
			array('title' => 'Bookmark', 'value'
=> 'bookmark'),
			array('title' => 'Help', 'value' =>
'help'),
			array('title' => 'License', 'value'
=> 'license'),
			array('title' => 'Lightbox', 'value'
=> 'lightbox'),
			array('title' => 'Next', 'value' =>
'next'),
			array('title' => 'No Follow', 'value'
=> 'nofollow'),
			array('title' => 'No Referrer', 'value'
=> 'noreferrer'),
			array('title' => 'Prefetch', 'value'
=> 'prefetch'),
			array('title' => 'Prev', 'value' =>
'prev'),
			array('title' => 'Search', 'value'
=> 'search'),
			array('title' => 'Tag', 'value' =>
'tag'),
		);

		/**
		 * Shrink the buttons if not on a mobile or if mobile view is off.
		 * If mobile view is on force into simple mode and enlarge the buttons
		 **/
		if (!$this->app->client->mobile)
		{
			$scriptOptions['toolbar_items_size'] = 'small';
		}
		elseif ($levelParams->get('mobile', 0))
		{
			$scriptOptions['menubar'] = false;
			unset($scriptOptions['toolbar2']);
		}

		$options['tinyMCE']['default'] = $scriptOptions;

		$doc->addStyleDeclaration('.mce-in { padding: 5px 10px
!important;}');
		$doc->addScriptOptions('plg_editor_tinymce', $options);

		return $editor;
	}

	/**
	 * Get the toggle editor button
	 *
	 * @param   string  $name  Editor name
	 *
	 * @return  string
	 */
	private function _toogleButton($name)
	{
		return JLayoutHelper::render('joomla.tinymce.togglebutton',
$name);
	}

	/**
	 * Get the XTD buttons and render them inside tinyMCE
	 *
	 * @param   string  $name      the id of the editor field
	 * @param   string  $excluded  the buttons that should be hidden
	 *
	 * @return array
	 */
	private function tinyButtons($name, $excluded)
	{
		// Get the available buttons
		$buttons = $this->_subject->getButtons($name, $excluded);

		// Init the arrays for the buttons
		$tinyBtns  = array();
		$btnsNames = array();

		// Build the script
		foreach ($buttons as $i => $button)
		{
			if ($button->get('name'))
			{
				// Set some vars
				$name    = 'button-' . $i . str_replace(' ',
'', $button->get('text'));
				$title   = $button->get('text');
				$onclick = $button->get('onclick') ?: null;
				$options = $button->get('options');
				$icon    = $button->get('name');

				if ($button->get('link') !== '#')
				{
					$href = JUri::base() . $button->get('link');
				}
				else
				{
					$href = null;
				}

				// We do some hack here to set the correct icon for 3PD buttons
				$icon = 'none icon-' . $icon;

				$tempConstructor = array();

				// Now we can built the script
				$tempConstructor[] = '!(function(){';

				// Get the modal width/height
				if ($options && is_scalar($options))
				{
					$tempConstructor[] = 'var getBtnOptions=new Function("return
' . addslashes($options) . '"),';
					$tempConstructor[] = 'btnOptions=getBtnOptions(),';
					$tempConstructor[] =
'modalWidth=btnOptions.size&&btnOptions.size.x?btnOptions.size.x:null,';
					$tempConstructor[] =
'modalHeight=btnOptions.size&&btnOptions.size.y?btnOptions.size.y:null;';
				}
				else
				{
					$tempConstructor[] = 'var
btnOptions={},modalWidth=null,modalHeight=null;';
				}

				// Now we can built the script
				// AddButton starts here
				$tempConstructor[] = 'editor.addButton("' . $name .
'",{';
				$tempConstructor[] = 'text:"' . $title .
'",';
				$tempConstructor[] = 'title:"' . $title .
'",';
				$tempConstructor[] = 'icon:"' . $icon .
'",';

				// Onclick starts here
				$tempConstructor[] = 'onclick:function(){';

				if ($href || $button->get('modal'))
				{
					// TinyMCE standard modal options
					$tempConstructor[] = 'var modalOptions={';
					$tempConstructor[] = 'title:"' . $title .
'",';
					$tempConstructor[] = 'url:"' . $href .
'",';
					$tempConstructor[] = 'buttons:[{text:
"Close",onclick:"close"}]';
					$tempConstructor[] = '};';

					// Set width/height
					$tempConstructor[] =
'if(modalWidth){modalOptions.width=modalWidth;}';
					$tempConstructor[] = 'if(modalHeight){modalOptions.height =
modalHeight;}';
					$tempConstructor[] = 'var
win=editor.windowManager.open(modalOptions);';

					if (JFactory::getApplication()->client->mobile)
					{
						$tempConstructor[] = 'win.fullscreen(true);';
					}

					if ($onclick && ($button->get('modal') || $href))
					{
						// Adds callback for close button
						$tempConstructor[] = $onclick . ';';
					}
				}
				else
				{
					// Adds callback for the button, eg: readmore
					$tempConstructor[] = $onclick . ';';
				}

				// Onclick ends here
				$tempConstructor[] = '}';

				// AddButton ends here
				$tempConstructor[] = '});';

				// IIFE ends here
				$tempConstructor[] = '})();';

				// The array with the toolbar buttons
				$btnsNames[] = $name . ' | ';

				// The array with code for each button
				$tinyBtns[] = implode('', $tempConstructor);
			}
		}

		return array(
				'names'  => $btnsNames,
				'script' => $tinyBtns
		);
	}

	/**
	 * Get the global text filters to arbitrary text as per settings for
current user groups
	 *
	 * @return  JFilterInput
	 *
	 * @since   3.6
	 */
	protected static function getGlobalFilters()
	{
		// Filter settings
		$config     = JComponentHelper::getParams('com_config');
		$user       = JFactory::getUser();
		$userGroups = JAccess::getGroupsByUser($user->get('id'));

		$filters = $config->get('filters');

		$blackListTags       = array();
		$blackListAttributes = array();

		$customListTags       = array();
		$customListAttributes = array();

		$whiteListTags       = array();
		$whiteListAttributes = array();

		$whiteList  = false;
		$blackList  = false;
		$customList = false;
		$unfiltered = false;

		// Cycle through each of the user groups the user is in.
		// Remember they are included in the public group as well.
		foreach ($userGroups as $groupId)
		{
			// May have added a group but not saved the filters.
			if (!isset($filters->$groupId))
			{
				continue;
			}

			// Each group the user is in could have different filtering properties.
			$filterData = $filters->$groupId;
			$filterType = strtoupper($filterData->filter_type);

			if ($filterType === 'NH')
			{
				// Maximum HTML filtering.
			}
			elseif ($filterType === 'NONE')
			{
				// No HTML filtering.
				$unfiltered = true;
			}
			else
			{
				// Blacklist or whitelist.
				// Preprocess the tags and attributes.
				$tags           = explode(',', $filterData->filter_tags);
				$attributes     = explode(',',
$filterData->filter_attributes);
				$tempTags       = array();
				$tempAttributes = array();

				foreach ($tags as $tag)
				{
					$tag = trim($tag);

					if ($tag)
					{
						$tempTags[] = $tag;
					}
				}

				foreach ($attributes as $attribute)
				{
					$attribute = trim($attribute);

					if ($attribute)
					{
						$tempAttributes[] = $attribute;
					}
				}

				// Collect the blacklist or whitelist tags and attributes.
				// Each list is cummulative.
				if ($filterType === 'BL')
				{
					$blackList           = true;
					$blackListTags       = array_merge($blackListTags, $tempTags);
					$blackListAttributes = array_merge($blackListAttributes,
$tempAttributes);
				}
				elseif ($filterType === 'CBL')
				{
					// Only set to true if Tags or Attributes were added
					if ($tempTags || $tempAttributes)
					{
						$customList           = true;
						$customListTags       = array_merge($customListTags, $tempTags);
						$customListAttributes = array_merge($customListAttributes,
$tempAttributes);
					}
				}
				elseif ($filterType === 'WL')
				{
					$whiteList           = true;
					$whiteListTags       = array_merge($whiteListTags, $tempTags);
					$whiteListAttributes = array_merge($whiteListAttributes,
$tempAttributes);
				}
			}
		}

		// Remove duplicates before processing (because the blacklist uses both
sets of arrays).
		$blackListTags        = array_unique($blackListTags);
		$blackListAttributes  = array_unique($blackListAttributes);
		$customListTags       = array_unique($customListTags);
		$customListAttributes = array_unique($customListAttributes);
		$whiteListTags        = array_unique($whiteListTags);
		$whiteListAttributes  = array_unique($whiteListAttributes);

		// Unfiltered assumes first priority.
		if ($unfiltered)
		{
			// Dont apply filtering.
			return false;
		}
		else
		{
			// Custom blacklist precedes Default blacklist
			if ($customList)
			{
				$filter = JFilterInput::getInstance(array(), array(), 1, 1);

				// Override filter's default blacklist tags and attributes
				if ($customListTags)
				{
					$filter->tagBlacklist = $customListTags;
				}

				if ($customListAttributes)
				{
					$filter->attrBlacklist = $customListAttributes;
				}
			}
			// Blacklists take second precedence.
			elseif ($blackList)
			{
				// Remove the white-listed tags and attributes from the black-list.
				$blackListTags       = array_diff($blackListTags, $whiteListTags);
				$blackListAttributes = array_diff($blackListAttributes,
$whiteListAttributes);

				$filter = JFilterInput::getInstance($blackListTags,
$blackListAttributes, 1, 1);

				// Remove whitelisted tags from filter's default blacklist
				if ($whiteListTags)
				{
					$filter->tagBlacklist = array_diff($filter->tagBlacklist,
$whiteListTags);
				}

				// Remove whitelisted attributes from filter's default blacklist
				if ($whiteListAttributes)
				{
					$filter->attrBlacklist = array_diff($filter->attrBlacklist,
$whiteListAttributes);
				}
			}
			// Whitelists take third precedence.
			elseif ($whiteList)
			{
				// Turn off XSS auto clean
				$filter = JFilterInput::getInstance($whiteListTags,
$whiteListAttributes, 0, 0, 0);
			}
			// No HTML takes last place.
			else
			{
				$filter = JFilterInput::getInstance();
			}

			return $filter;
		}
	}

	/**
	 * Return list of known TinyMCE buttons
	 *
	 * @return array
	 *
	 * @since 3.7.0
	 */
	public static function getKnownButtons()
	{
		// See https://www.tinymce.com/docs/demo/full-featured/
		// And https://www.tinymce.com/docs/plugins/
		$buttons = array(

			// General buttons
			'|'              => array('label' =>
JText::_('PLG_TINY_TOOLBAR_BUTTON_SEPARATOR'), 'text'
=> '|'),

			'undo'           => array('label' =>
'Undo'),
			'redo'           => array('label' =>
'Redo'),

			'bold'           => array('label' =>
'Bold'),
			'italic'         => array('label' =>
'Italic'),
			'underline'      => array('label' =>
'Underline'),
			'strikethrough'  => array('label' =>
'Strikethrough'),
			'styleselect'    => array('label' =>
JText::_('PLG_TINY_TOOLBAR_BUTTON_STYLESELECT'), 'text'
=> 'Formats'),
			'formatselect'   => array('label' =>
JText::_('PLG_TINY_TOOLBAR_BUTTON_FORMATSELECT'),
'text' => 'Paragraph'),
			'fontselect'     => array('label' =>
JText::_('PLG_TINY_TOOLBAR_BUTTON_FONTSELECT'), 'text'
=> 'Font Family'),
			'fontsizeselect' => array('label' =>
JText::_('PLG_TINY_TOOLBAR_BUTTON_FONTSIZESELECT'),
'text' => 'Font Sizes'),

			'alignleft'     => array('label' =>
'Align left'),
			'aligncenter'   => array('label' =>
'Align center'),
			'alignright'    => array('label' =>
'Align right'),
			'alignjustify'  => array('label' =>
'Justify'),

			'outdent'       => array('label' =>
'Decrease indent'),
			'indent'        => array('label' =>
'Increase indent'),

			'bullist'       => array('label' =>
'Bullet list'),
			'numlist'       => array('label' =>
'Numbered list'),

			'link'          => array('label' =>
'Insert/edit link', 'plugin' => 'link'),
			'unlink'        => array('label' =>
'Remove link', 'plugin' => 'link'),

			'subscript'     => array('label' =>
'Subscript'),
			'superscript'   => array('label' =>
'Superscript'),
			'blockquote'    => array('label' =>
'Blockquote'),

			'cut'           => array('label' =>
'Cut'),
			'copy'          => array('label' =>
'Copy'),
			'paste'         => array('label' =>
'Paste', 'plugin' => 'paste'),
			'pastetext'     => array('label' =>
'Paste as text', 'plugin' => 'paste'),
			'removeformat'  => array('label' =>
'Clear formatting'),

			// Buttons from the plugins
			'forecolor'      => array('label' =>
'Text color', 'plugin' => 'textcolor'),
			'backcolor'      => array('label' =>
'Background color', 'plugin' =>
'textcolor'),
			'anchor'         => array('label' =>
'Anchor', 'plugin' => 'anchor'),
			'hr'             => array('label' =>
'Horizontal line', 'plugin' => 'hr'),
			'ltr'            => array('label' =>
'Left to right', 'plugin' =>
'directionality'),
			'rtl'            => array('label' =>
'Right to left', 'plugin' =>
'directionality'),
			'code'           => array('label' =>
'Source code', 'plugin' => 'code'),
			'codesample'     => array('label' =>
'Insert/Edit code sample', 'plugin' =>
'codesample'),
			'table'          => array('label' =>
'Table', 'plugin' => 'table'),
			'charmap'        => array('label' =>
'Special character', 'plugin' =>
'charmap'),
			'visualchars'    => array('label' =>
'Show invisible characters', 'plugin' =>
'visualchars'),
			'visualblocks'   => array('label' =>
'Show blocks', 'plugin' =>
'visualblocks'),
			'nonbreaking'    => array('label' =>
'Nonbreaking space', 'plugin' =>
'nonbreaking'),
			'emoticons'      => array('label' =>
'Emoticons', 'plugin' => 'emoticons'),
			'image'          => array('label' =>
'Insert/edit image', 'plugin' => 'image'),
			'media'          => array('label' =>
'Insert/edit video', 'plugin' => 'media'),
			'pagebreak'      => array('label' =>
'Page break', 'plugin' => 'pagebreak'),
			'print'          => array('label' =>
'Print', 'plugin' => 'print'),
			'preview'        => array('label' =>
'Preview', 'plugin' => 'preview'),
			'fullscreen'     => array('label' =>
'Fullscreen', 'plugin' => 'fullscreen'),
			'template'       => array('label' =>
'Insert template', 'plugin' =>
'template'),
			'searchreplace'  => array('label' =>
'Find and replace', 'plugin' =>
'searchreplace'),
			'insertdatetime' => array('label' =>
'Insert date/time', 'plugin' =>
'insertdatetime'),
			// 'spellchecker'   => array('label' =>
'Spellcheck', 'plugin' => 'spellchecker'),
		);

		return $buttons;
	}

	/**
	 * Return toolbar presets
	 *
	 * @return array
	 *
	 * @since 3.7.0
	 */
	public static function getToolbarPreset()
	{
		$preset = array();

		$preset['simple'] = array(
			'menu' => array(),
			'toolbar1' => array(
				'bold', 'underline', 'strikethrough',
'|',
				'undo', 'redo', '|',
				'bullist', 'numlist', '|',
				'pastetext'
			),
			'toolbar2' => array(),
		);

		$preset['medium'] = array(
			'menu' => array('edit', 'insert',
'view', 'format', 'table',
'tools'),
			'toolbar1' => array(
				'bold', 'italic', 'underline',
'strikethrough', '|',
				'alignleft', 'aligncenter', 'alignright',
'alignjustify', '|',
				'formatselect', '|',
				'bullist', 'numlist', '|',
				'outdent', 'indent', '|',
				'undo', 'redo', '|',
				'link', 'unlink', 'anchor',
'code', '|',
				'hr', 'table', '|',
				'subscript', 'superscript', '|',
				'charmap', 'pastetext' , 'preview'
			),
			'toolbar2' => array(),
		);

		$preset['advanced'] = array(
			'menu'     => array('edit', 'insert',
'view', 'format', 'table',
'tools'),
			'toolbar1' => array(
				'bold', 'italic', 'underline',
'strikethrough', '|',
				'alignleft', 'aligncenter', 'alignright',
'alignjustify', '|',
				'styleselect', '|',
				'formatselect', 'fontselect',
'fontsizeselect', '|',
				'searchreplace', '|',
				'bullist', 'numlist', '|',
				'outdent', 'indent', '|',
				'undo', 'redo', '|',
				'link', 'unlink', 'anchor',
'image', '|',
				'code', '|',
				'forecolor', 'backcolor', '|',
				'fullscreen', '|',
				'table', '|',
				'subscript', 'superscript', '|',
				'charmap', 'emoticons', 'media',
'hr', 'ltr', 'rtl', '|',
				'cut', 'copy', 'paste',
'pastetext', '|',
				'visualchars', 'visualblocks',
'nonbreaking', 'blockquote', 'template',
'|',
				'print', 'preview', 'codesample',
'insertdatetime', 'removeformat',
			),
			'toolbar2' => array(),
		);

		return $preset;
	}

	/**
	 * Gets the plugin extension id.
	 *
	 * @return  int  The plugin id.
	 *
	 * @since   3.7.0
	 */
	private function getPluginId()
	{
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
					->select($db->quoteName('extension_id'))
					->from($db->quoteName('#__extensions'))
					->where($db->quoteName('folder') . ' = ' .
$db->quote($this->_type))
					->where($db->quoteName('element') . ' = ' .
$db->quote($this->_name));
		$db->setQuery($query);

		return (int) $db->loadResult();
	}

	/**
	 * Display the editor area.
	 *
	 * @param   string   $name     The name of the editor area.
	 * @param   string   $content  The content of the field.
	 * @param   string   $width    The width of the editor area.
	 * @param   string   $height   The height of the editor area.
	 * @param   int      $col      The number of columns for the editor area.
	 * @param   int      $row      The number of rows for the editor area.
	 * @param   boolean  $buttons  True and the editor buttons will be
displayed.
	 * @param   string   $id       An optional ID for the textarea. If not
supplied the name is used.
	 * @param   string   $asset    The object asset
	 * @param   object   $author   The author.
	 * @param   array    $params   Associative array of editor parameters.
	 *
	 * @return  string
	 *
	 * @since  3.7.0
	 *
	 * @deprecated 4.0
	 */
	private function onDisplayLegacy(
		$name, $content, $width, $height, $col, $row, $buttons = true, $id =
null, $asset = null, $author = null, $params = array())
	{
		if (empty($id))
		{
			$id = $name;
		}

		$id            = preg_replace('/(\s|[^A-Za-z0-9_])+/',
'_', $id);
		$nameGroup     = explode('[',
preg_replace('/\[\]|\]/', '', $name));
		$fieldName     = end($nameGroup);
		$scriptOptions = array();

		// Check for existing options
		$doc     = JFactory::getDocument();
		$options = $doc->getScriptOptions('plg_editor_tinymce');

		// Only add "px" to width and height if they are not given as a
percentage
		if (is_numeric($width))
		{
			$width .= 'px';
		}

		if (is_numeric($height))
		{
			$height .= 'px';
		}

		// Data object for the layout
		$textarea = new stdClass;
		$textarea->name    = $name;
		$textarea->id      = $id;
		$textarea->class   = 'mce_editable joomla-editor-tinymce';
		$textarea->cols    = $col;
		$textarea->rows    = $row;
		$textarea->width   = $width;
		$textarea->height  = $height;
		$textarea->content = $content;

		// Set editor to readonly mode
		$textarea->readonly = !empty($params['readonly']);

		// Render Editor markup
		$editor = '<div class="editor
js-editor-tinymce">';
		$editor .= JLayoutHelper::render('joomla.tinymce.textarea',
$textarea);
		$editor .= $this->_toogleButton($id);
		$editor .= '</div>';

		// Prepare instance specific options, actually the ext-buttons
		if
(empty($options['tinyMCE'][$fieldName]['joomlaExtButtons']))
		{
			$btns = $this->tinyButtons($id, $buttons);

			if (!empty($btns['names']))
			{
				JHtml::_('script',
'editors/tinymce/tiny-close.min.js', array('version'
=> 'auto', 'relative' => true),
array('defer' => 'defer'));
			}

			// Set editor to readonly mode
			if (!empty($params['readonly']))
			{
				$options['tinyMCE'][$fieldName]['readonly'] = 1;
			}

			$options['tinyMCE'][$fieldName]['joomlaMergeDefaults']
= true;
			$options['tinyMCE'][$fieldName]['joomlaExtButtons'] 
  = $btns;

			$doc->addScriptOptions('plg_editor_tinymce', $options,
false);
		}

		// Setup Default options for the Editor script

		// Check whether we already have them
		if (!empty($options['tinyMCE']['default']))
		{
			return $editor;
		}

		$app      = JFactory::getApplication();
		$user     = JFactory::getUser();
		$language = JFactory::getLanguage();
		$mode     = (int) $this->params->get('mode', 1);
		$theme    = 'modern';

		// List the skins
		$skindirs = glob(JPATH_ROOT . '/media/editors/tinymce/skins' .
'/*', GLOB_ONLYDIR);


		// Set the selected skin
		$skin = 'lightgray';
		$side = $app->isClient('administrator') ?
'skin_admin' : 'skin';

		if ((int) $this->params->get($side, 0) < count($skindirs))
		{
			$skin = basename($skindirs[(int) $this->params->get($side, 0)]);
		}

		$langMode        = $this->params->get('lang_mode', 0);
		$langPrefix      = $this->params->get('lang_code',
'en');

		if ($langMode)
		{
			if (file_exists(JPATH_ROOT . "/media/editors/tinymce/langs/" .
$language->getTag() . ".js"))
			{
				$langPrefix = $language->getTag();
			}
			elseif (file_exists(JPATH_ROOT .
"/media/editors/tinymce/langs/" . substr($language->getTag(),
0, strpos($language->getTag(), '-')) . ".js"))
			{
				$langPrefix = substr($language->getTag(), 0,
strpos($language->getTag(), '-'));
			}
			else
			{
				$langPrefix = "en";
			}
		}

		$text_direction = 'ltr';

		if ($language->isRtl())
		{
			$text_direction = 'rtl';
		}

		$use_content_css    = $this->params->get('content_css',
1);
		$content_css_custom =
$this->params->get('content_css_custom', '');

		/*
		 * Lets get the default template for the site application
		 */
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true)
					->select('template')
					->from('#__template_styles')
					->where('client_id=0 AND home=' .
$db->quote('1'));

		$db->setQuery($query);

		try
		{
			$template = $db->loadResult();
		}
		catch (RuntimeException $e)
		{
			$app->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'),
'error');

			return;
		}

		$content_css    = null;
		$templates_path = JPATH_SITE . '/templates';

		// Loading of css file for 'styles' dropdown
		if ($content_css_custom)
		{
			// If URL, just pass it to $content_css
			if (strpos($content_css_custom, 'http') !== false)
			{
				$content_css = $content_css_custom;
			}

			// If it is not a URL, assume it is a file name in the current template
folder
			else
			{
				$content_css = JUri::root(true) . '/templates/' . $template .
'/css/' . $content_css_custom;

				// Issue warning notice if the file is not found (but pass name to
$content_css anyway to avoid TinyMCE error
				if (!file_exists($templates_path . '/' . $template .
'/css/' . $content_css_custom))
				{
					$msg =
sprintf(JText::_('PLG_TINY_ERR_CUSTOMCSSFILENOTPRESENT'),
$content_css_custom);
					JLog::add($msg, JLog::WARNING, 'jerror');
				}
			}
		}
		else
		{
			// Process when use_content_css is Yes and no custom file given
			if ($use_content_css)
			{
				// First check templates folder for default template
				// if no editor.css file in templates folder, check system template
folder
				if (!file_exists($templates_path . '/' . $template .
'/css/editor.css'))
				{
					// If no editor.css file in system folder, show alert
					if (!file_exists($templates_path .
'/system/css/editor.css'))
					{
						JLog::add(JText::_('PLG_TINY_ERR_EDITORCSSFILENOTPRESENT'),
JLog::WARNING, 'jerror');
					}
					else
					{
						$content_css = JUri::root(true) .
'/templates/system/css/editor.css';
					}
				}
				else
				{
					$content_css = JUri::root(true) . '/templates/' . $template
. '/css/editor.css';
				}
			}
		}

		$ignore_filter = false;

		// Text filtering
		if ($this->params->get('use_config_textfilters', 0))
		{
			// Use filters from com_config
			$filter = static::getGlobalFilters();

			$ignore_filter = $filter === false;

			$tagBlacklist  = !empty($filter->tagBlacklist) ?
$filter->tagBlacklist : array();
			$attrBlacklist = !empty($filter->attrBlacklist) ?
$filter->attrBlacklist : array();
			$tagArray      = !empty($filter->tagArray) ? $filter->tagArray :
array();
			$attrArray     = !empty($filter->attrArray) ? $filter->attrArray :
array();

			$invalid_elements  = implode(',', array_merge($tagBlacklist,
$attrBlacklist, $tagArray, $attrArray));

			// Valid elements are all whitelist entries in com_config, which are now
missing in the tagBlacklist
			$default_filter = JFilterInput::getInstance();
			$valid_elements =	implode(',',
array_diff($default_filter->tagBlacklist, $tagBlacklist));

			$extended_elements = '';
		}
		else
		{
			// Use filters from TinyMCE params
			$invalid_elements  =
$this->params->get('invalid_elements',
'script,applet,iframe');
			$extended_elements =
$this->params->get('extended_elements', '');
			$valid_elements    =
$this->params->get('valid_elements', '');
		}

		// Advanced Options
		$access = $user->getAuthorisedViewLevels();

		// Flip for performance, so we can direct check for the key
isset($access[$key])
		$access = array_flip($access);

		$html_height = $this->params->get('html_height',
'550');
		$html_width  = $this->params->get('html_width',
'');

		if ($html_width == 750)
		{
			$html_width = '';
		}

		// Image advanced options
		$image_advtab = $this->params->get('image_advtab', true);

		if (isset($access[$image_advtab]))
		{
			$image_advtab = true;
		}
		else
		{
			$image_advtab = false;
		}

		// The param is true for vertical resizing only, false or both
		$resizing          = $this->params->get('resizing',
'1');
		$resize_horizontal =
$this->params->get('resize_horizontal', '1');

		if ($resizing || $resizing == 'true')
		{
			if ($resize_horizontal || $resize_horizontal == 'true')
			{
				$resizing = 'both';
			}
			else
			{
				$resizing = true;
			}
		}
		else
		{
			$resizing = false;
		}

		$toolbar1_add   = array();
		$toolbar2_add   = array();
		$toolbar3_add   = array();
		$toolbar4_add   = array();
		$elements       = array();
		$plugins        = array(
			'autolink',
			'lists',
			'image',
			'charmap',
			'print',
			'preview',
			'anchor',
			'pagebreak',
			'code',
			'save',
			'textcolor',
			'colorpicker',
			'importcss');
		$toolbar1_add[] = 'bold';
		$toolbar1_add[] = 'italic';
		$toolbar1_add[] = 'underline';
		$toolbar1_add[] = 'strikethrough';

		// Alignment buttons
		$alignment = $this->params->get('alignment', 1);

		if (isset($access[$alignment]))
		{
			$toolbar1_add[] = '|';
			$toolbar1_add[] = 'alignleft';
			$toolbar1_add[] = 'aligncenter';
			$toolbar1_add[] = 'alignright';
			$toolbar1_add[] = 'alignjustify';
		}

		$toolbar1_add[] = '|';
		$toolbar1_add[] = 'styleselect';
		$toolbar1_add[] = '|';
		$toolbar1_add[] = 'formatselect';

		// Fonts
		$fonts = $this->params->get('fonts', 1);

		if (isset($access[$fonts]))
		{
			$toolbar1_add[] = 'fontselect';
			$toolbar1_add[] = 'fontsizeselect';
		}

		// Search & replace
		$searchreplace = $this->params->get('searchreplace', 1);

		if (isset($access[$searchreplace]))
		{
			$plugins[]      = 'searchreplace';
			$toolbar2_add[] = 'searchreplace';
		}

		$toolbar2_add[] = '|';
		$toolbar2_add[] = 'bullist';
		$toolbar2_add[] = 'numlist';
		$toolbar2_add[] = '|';
		$toolbar2_add[] = 'outdent';
		$toolbar2_add[] = 'indent';
		$toolbar2_add[] = '|';
		$toolbar2_add[] = 'undo';
		$toolbar2_add[] = 'redo';
		$toolbar2_add[] = '|';

		// Insert date and/or time plugin
		$insertdate = $this->params->get('insertdate', 1);

		if (isset($access[$insertdate]))
		{
			$plugins[]      = 'insertdatetime';
			$toolbar4_add[] = 'inserttime';
		}

		// Link plugin
		$link = $this->params->get('link', 1);

		if (isset($access[$link]))
		{
			$plugins[]      = 'link';
			$toolbar2_add[] = 'link';
			$toolbar2_add[] = 'unlink';
		}

		$toolbar2_add[] = 'anchor';
		$toolbar2_add[] = 'image';
		$toolbar2_add[] = '|';
		$toolbar2_add[] = 'code';

		// Colors
		$colors = $this->params->get('colors', 1);

		if (isset($access[$colors]))
		{
			$toolbar2_add[] = '|';
			$toolbar2_add[] = 'forecolor,backcolor';
		}

		// Fullscreen
		$fullscreen = $this->params->get('fullscreen', 1);

		if (isset($access[$fullscreen]))
		{
			$plugins[]      = 'fullscreen';
			$toolbar2_add[] = '|';
			$toolbar2_add[] = 'fullscreen';
		}

		// Table
		$table = $this->params->get('table', 1);

		if (isset($access[$table]))
		{
			$plugins[]      = 'table';
			$toolbar3_add[] = 'table';
			$toolbar3_add[] = '|';
		}

		$toolbar3_add[] = 'subscript';
		$toolbar3_add[] = 'superscript';
		$toolbar3_add[] = '|';
		$toolbar3_add[] = 'charmap';

		// Emotions
		$smilies = $this->params->get('smilies', 1);

		if (isset($access[$smilies]))
		{
			$plugins[]      = 'emoticons';
			$toolbar3_add[] = 'emoticons';
		}

		// Media plugin
		$media = $this->params->get('media', 1);

		if (isset($access[$media]))
		{
			$plugins[]      = 'media';
			$toolbar3_add[] = 'media';
		}

		// Horizontal line
		$hr = $this->params->get('hr', 1);

		if (isset($access[$hr]))
		{
			$plugins[]      = 'hr';
			$elements[]     = 'hr[id|title|alt|class|width|size|noshade]';
			$toolbar3_add[] = 'hr';
		}
		else
		{
			$elements[] = 'hr[id|class|title|alt]';
		}

		// RTL/LTR buttons
		$directionality = $this->params->get('directionality',
1);

		if (isset($access[$directionality]))
		{
			$plugins[]      = 'directionality';
			$toolbar3_add[] = 'ltr rtl';
		}

		if ($extended_elements != "")
		{
			$elements = explode(',', $extended_elements);
		}

		$toolbar4_add[] = 'cut';
		$toolbar4_add[] = 'copy';

		// Paste
		$paste = $this->params->get('paste', 1);

		if (isset($access[$paste]))
		{
			$plugins[]      = 'paste';
			$toolbar4_add[] = 'paste';
		}

		$toolbar4_add[] = '|';

		// Visualchars
		$visualchars = $this->params->get('visualchars', 1);

		if (isset($access[$visualchars]))
		{
			$plugins[]      = 'visualchars';
			$toolbar4_add[] = 'visualchars';
		}

		// Visualblocks
		$visualblocks = $this->params->get('visualblocks', 1);

		if (isset($access[$visualblocks]))
		{
			$plugins[]      = 'visualblocks';
			$toolbar4_add[] = 'visualblocks';
		}

		// Non-breaking
		$nonbreaking = $this->params->get('nonbreaking', 1);

		if (isset($access[$nonbreaking]))
		{
			$plugins[]      = 'nonbreaking';
			$toolbar4_add[] = 'nonbreaking';
		}

		// Blockquote
		$blockquote = $this->params->get('blockquote', 1);

		if (isset($access[$blockquote]))
		{
			$toolbar4_add[] = 'blockquote';
		}

		// Template
		$template = $this->params->get('template', 1);
		$templates = array();

		if (isset($access[$template]))
		{
			$plugins[]      = 'template';
			$toolbar4_add[] = 'template';

			// Note this check for the template_list.js file will be removed in
Joomla 4.0
			if (is_file(JPATH_ROOT .
"/media/editors/tinymce/templates/template_list.js"))
			{
				// If using the legacy file we need to include and input the files the
new way
				$str = file_get_contents(JPATH_ROOT .
"/media/editors/tinymce/templates/template_list.js");

				// Find from one [ to the last ]
				$matches = array();
				preg_match_all('/\[.*\]/', $str, $matches);

				// Set variables
				foreach ($matches['0'] as $match)
				{
					$values = array();
					preg_match_all('/\".*\"/', $match, $values);
					$result       = trim($values["0"]["0"],
'"');
					$final_result = explode(',', $result);

					$templates[] = array(
						'title' => trim($final_result['0'], '
" '),
						'description' => trim($final_result['2'],
' " '),
						'url' => JUri::root(true) . '/' .
trim($final_result['1'], ' " '),
					);
				}

			}
			else
			{
				foreach (glob(JPATH_ROOT .
'/media/editors/tinymce/templates/*.html') as $filename)
				{
					$filename = basename($filename, '.html');

					if ($filename !== 'index')
					{
						$lang        = JFactory::getLanguage();
						$title       = $filename;
						$description = ' ';

						if ($lang->hasKey('PLG_TINY_TEMPLATE_' .
strtoupper($filename) . '_TITLE'))
						{
							$title = JText::_('PLG_TINY_TEMPLATE_' .
strtoupper($filename) . '_TITLE');
						}

						if ($lang->hasKey('PLG_TINY_TEMPLATE_' .
strtoupper($filename) . '_DESC'))
						{
							$description = JText::_('PLG_TINY_TEMPLATE_' .
strtoupper($filename) . '_DESC');
						}

						$templates[] = array(
							'title' => $title,
							'description' => $description,
							'url' => JUri::root(true) .
'/media/editors/tinymce/templates/' . $filename .
'.html',
						);
					}
				}
			}
		}

		// Print
		$print = $this->params->get('print', 1);

		if (isset($access[$print]))
		{
			$plugins[]      = 'print';
			$toolbar4_add[] = '|';
			$toolbar4_add[] = 'print';
			$toolbar4_add[] = 'preview';
		}

		// Spellchecker
		$spell = $this->params->get('spell', 0);

		if (isset($access[$spell]))
		{
			$plugins[]      = 'spellchecker';
			$toolbar4_add[] = '|';
			$toolbar4_add[] = 'spellchecker';
		}

		// Wordcount
		$wordcount = $this->params->get('wordcount', 1);

		if (isset($access[$wordcount]))
		{
			$plugins[] = 'wordcount';
		}

		// Advlist
		$advlist = $this->params->get('advlist', 1);

		if (isset($access[$advlist]))
		{
			$plugins[] = 'advlist';
		}

		// Codesample
		$advlist = $this->params->get('code_sample', 1);

		if (isset($access[$advlist]))
		{
			$plugins[]      = 'codesample';
			$toolbar4_add[] = 'codesample';
		}

		// Autosave
		$autosave = $this->params->get('autosave', 1);

		if (isset($access[$autosave]))
		{
			$plugins[] = 'autosave';
		}

		// Context menu
		$contextmenu = $this->params->get('contextmenu', 1);

		if (isset($access[$contextmenu]))
		{
			$plugins[] = 'contextmenu';
		}

		$custom_plugin = $this->params->get('custom_plugin',
'');

		if ($custom_plugin != "")
		{
			$plugins[] = $custom_plugin;
		}

		$custom_button = $this->params->get('custom_button',
'');

		if ($custom_button != "")
		{
			$toolbar4_add[] = $custom_button;
		}

		// Drag and drop Images
		$externalPlugins = array();
		$allowImgPaste   = false;
		$dragdrop        = $this->params->get('drag_drop', 1);

		if ($dragdrop && $user->authorise('core.create',
'com_media'))
		{
			$allowImgPaste = true;
			$isSubDir      = '';
			$session       = JFactory::getSession();
			$uploadUrl     = JUri::base() .
'index.php?option=com_media&task=file.upload&tmpl=component&'
								. $session->getName() . '=' . $session->getId()
								. '&' . JSession::getFormToken() . '=1'
								. '&asset=image&format=json';

			if ($app->isClient('site'))
			{
				$uploadUrl = htmlentities($uploadUrl, 0, 'UTF-8', false);
			}

			// Is Joomla installed in subdirectory
			if (JUri::root(true) != '/')
			{
				$isSubDir = JUri::root(true);
			}

			JText::script('PLG_TINY_ERR_UNSUPPORTEDBROWSER');

			$scriptOptions['setCustomDir']    = $isSubDir;
			$scriptOptions['mediaUploadPath'] =
$this->params->get('path', '');
			$scriptOptions['uploadUri']       = $uploadUrl;

			$externalPlugins = array(
				array(
					'jdragdrop' => HTMLHelper::_(
						'script',
						'editors/tinymce/plugins/dragdrop/plugin.min.js',
						array('relative' => true, 'version' =>
'auto', 'pathOnly' => true)
					),
				),
			);
		}

		// Prepare config variables
		$plugins  = implode(',', $plugins);
		$elements = implode(',', $elements);

		// Prepare config variables
		$toolbar1 = implode(' ', $toolbar1_add) . ' | '
					. implode(' ', $toolbar2_add) . ' | '
					. implode(' ', $toolbar3_add) . ' | '
					. implode(' ', $toolbar4_add);

		// See if mobileVersion is activated
		$mobileVersion = $this->params->get('mobile', 0);

		$scriptOptions = array_merge(
			$scriptOptions,
			array(
			'suffix'  => '.min',
			'baseURL' => JUri::root(true) .
'/media/editors/tinymce',
			'directionality' => $text_direction,
			'language' => $langPrefix,
			'autosave_restore_when_empty' => false,
			'skin'   => $skin,
			'theme'  => $theme,
			'schema' => 'html5',

			// Cleanup/Output
			'inline_styles'    => true,
			'gecko_spellcheck' => true,
			'entity_encoding'  =>
$this->params->get('entity_encoding', 'raw'),
			'verify_html'      => !$ignore_filter,

			// URL
			'relative_urls'      => (bool)
$this->params->get('relative_urls', true),
			'remove_script_host' => false,

			// Layout
			'content_css'        => $content_css,
			'document_base_url'  => JUri::root(true) . '/',
			'paste_data_images'  => $allowImgPaste,
			'externalPlugins'    => json_encode($externalPlugins),
		)
		);

		if ($this->params->get('newlines'))
		{
			// Break
			$scriptOptions['force_br_newlines'] = true;
			$scriptOptions['force_p_newlines']  = false;
			$scriptOptions['forced_root_block'] = '';
		}
		else
		{
			// Paragraph
			$scriptOptions['force_br_newlines'] = false;
			$scriptOptions['force_p_newlines']  = true;
			$scriptOptions['forced_root_block'] = 'p';
		}

		/**
		 * Shrink the buttons if not on a mobile or if mobile view is off.
		 * If mobile view is on force into simple mode and enlarge the buttons
		 **/
		if (!$this->app->client->mobile)
		{
			$scriptOptions['toolbar_items_size'] = 'small';
		}
		elseif ($mobileVersion)
		{
			$mode = 0;
		}

		switch ($mode)
		{
			case 0: /* Simple mode*/
				$scriptOptions['menubar']  = false;
				$scriptOptions['toolbar1'] = 'bold italic underline
strikethrough | undo redo | bullist numlist | code';
				$scriptOptions['plugins']  = ' code';

				break;

			case 1:
			default: /* Advanced mode*/
				$toolbar1 = "bold italic underline strikethrough | alignleft
aligncenter alignright alignjustify | formatselect | bullist numlist "
							. "| outdent indent | undo redo | link unlink anchor code | hr
table | subscript superscript | charmap";

				$scriptOptions['valid_elements'] = $valid_elements;
				$scriptOptions['extended_valid_elements'] = $elements;
				$scriptOptions['invalid_elements'] = $invalid_elements;
				$scriptOptions['plugins']  = 'table link code hr charmap
autolink lists importcss ';
				$scriptOptions['toolbar1'] = $toolbar1;
				$scriptOptions['removed_menuitems'] =
'newdocument';
				$scriptOptions['importcss_append']  = true;
				$scriptOptions['height'] = $html_height;
				$scriptOptions['width']  = $html_width;
				$scriptOptions['resize'] = $resizing;

				break;

			case 2: /* Extended mode*/
				$scriptOptions['valid_elements'] = $valid_elements;
				$scriptOptions['extended_valid_elements'] = $elements;
				$scriptOptions['invalid_elements'] = $invalid_elements;
				$scriptOptions['plugins']  = $plugins;
				$scriptOptions['toolbar1'] = $toolbar1;
				$scriptOptions['removed_menuitems'] =
'newdocument';
				$scriptOptions['rel_list'] = array(
					array('title' => 'None', 'value'
=> ''),
					array('title' => 'Alternate', 'value'
=> 'alternate'),
					array('title' => 'Author', 'value'
=> 'author'),
					array('title' => 'Bookmark', 'value'
=> 'bookmark'),
					array('title' => 'Help', 'value'
=> 'help'),
					array('title' => 'License', 'value'
=> 'license'),
					array('title' => 'Lightbox', 'value'
=> 'lightbox'),
					array('title' => 'Next', 'value'
=> 'next'),
					array('title' => 'No Follow', 'value'
=> 'nofollow'),
					array('title' => 'No Referrer',
'value' => 'noreferrer'),
					array('title' => 'Prefetch', 'value'
=> 'prefetch'),
					array('title' => 'Prev', 'value'
=> 'prev'),
					array('title' => 'Search', 'value'
=> 'search'),
					array('title' => 'Tag', 'value' =>
'tag'),
				);
				$scriptOptions['importcss_append'] = true;
				$scriptOptions['image_advtab']     = $image_advtab;
				$scriptOptions['height']    = $html_height;
				$scriptOptions['width']     = $html_width;
				$scriptOptions['resize']    = $resizing;
				$scriptOptions['templates'] = $templates;

				break;
		}

		$options['tinyMCE']['default'] = $scriptOptions;

		$doc->addStyleDeclaration(".mce-in { padding: 5px 10px
!important;}");
		$doc->addScriptOptions('plg_editor_tinymce', $options);

		return $editor;
	}
}
editors/tinymce/tinymce.xml000064400000003267147357022240012075
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin"
group="editors" method="upgrade">
	<name>plg_editors_tinymce</name>
	<version>4.5.12</version>
	<creationDate>2005-2020</creationDate>
	<author>Tiny Technologies, Inc</author>
	<authorEmail>N/A</authorEmail>
	<authorUrl>https://www.tiny.cloud</authorUrl>
	<copyright>Tiny Technologies, Inc</copyright>
	<license>LGPL</license>
	<description>PLG_TINY_XML_DESCRIPTION</description>
	<files>
		<filename plugin="tinymce">tinymce.php</filename>
		<folder>fields</folder>
		<folder>form</folder>
	</files>
	<media destination="editors" folder="media">
		<folder>tinymce</folder>
	</media>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors_tinymce.ini</language>
		<language
tag="en-GB">en-GB.plg_editors_tinymce.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
				       name="configuration"
				       type="tinymcebuilder"
				       hiddenLabel="true"
				 />
			</fieldset>

			<fieldset name="advanced"
label="PLG_TINY_FIELD_LABEL_ADVANCEDPARAMS">
				<field
					name="sets_amount"
					type="number"
					label="PLG_TINY_FIELD_NUMBER_OF_SETS_LABEL"
					description="PLG_TINY_FIELD_NUMBER_OF_SETS_DESC"
					filter="int"
					validate="number"
					min="3"
					default="3"
				/>

				<field
					name="html_height"
					type="text"
					label="PLG_TINY_FIELD_HTMLHEIGHT_LABEL"
					description="PLG_TINY_FIELD_HTMLHEIGHT_DESC"
					default="550px"
				/>

				<field
					name="html_width"
					type="text"
					label="PLG_TINY_FIELD_HTMLWIDTH_LABEL"
					description="PLG_TINY_FIELD_HTMLWIDTH_DESC"
					default=""
				/>
			</fieldset>
		</fields>
	</config>
</extension>
editors-xtd/article/article.php000064400000003517147357022240012605
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.article
 *
 * @copyright   (C) 2009 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Article button
 *
 * @since  1.5
 */
class PlgButtonArticle extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   1.5
	 */
	public function onDisplay($name)
	{
		$input = JFactory::getApplication()->input;
		$user  = JFactory::getUser();

		// Can create in any category (component permission) or at least in one
category
		$canCreateRecords = $user->authorise('core.create',
'com_content')
			|| count($user->getAuthorisedCategories('com_content',
'core.create')) > 0;

		// Instead of checking edit on all records, we can use **same** check as
the form editing view
		$values = (array)
JFactory::getApplication()->getUserState('com_content.edit.article.id');
		$isEditingRecords = count($values);

		// This ACL check is probably a double-check (form view already performed
checks)
		$hasAccess = $canCreateRecords || $isEditingRecords;
		if (!$hasAccess)
		{
			return;
		}

		$link =
'index.php?option=com_content&amp;view=articles&amp;layout=modal&amp;tmpl=component&amp;'
			. JSession::getFormToken() . '=1&amp;editor=' . $name;

		$button = new JObject;
		$button->modal   = true;
		$button->class   = 'btn';
		$button->link    = $link;
		$button->text    = JText::_('PLG_ARTICLE_BUTTON_ARTICLE');
		$button->name    = 'file-add';
		$button->options = "{handler: 'iframe', size: {x: 800,
y: 500}}";

		return $button;
	}
}
editors-xtd/article/article.xml000064400000001430147357022240012606
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_article</name>
	<author>Joomla! Project</author>
	<creationDate>October 2009</creationDate>
	<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_ARTICLE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="article">article.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors-xtd_article.ini</language>
		<language
tag="en-GB">en-GB.plg_editors-xtd_article.sys.ini</language>
	</languages>
</extension>
editors-xtd/contact/contact.php000064400000002622147357022240012621
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.contact
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Contact button
 *
 * @since  3.7.0
 */
class PlgButtonContact extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   3.7.0
	 */
	public function onDisplay($name)
	{
		$user  = JFactory::getUser();

		if ($user->authorise('core.create', 'com_contact')
			|| $user->authorise('core.edit', 'com_contact')
			|| $user->authorise('core.edit.own',
'com_contact'))
		{
			// The URL for the contacts list
			$link =
'index.php?option=com_contact&amp;view=contacts&amp;layout=modal&amp;tmpl=component&amp;'
				. JSession::getFormToken() . '=1&amp;editor=' . $name;

			$button          = new JObject;
			$button->modal   = true;
			$button->class   = 'btn';
			$button->link    = $link;
			$button->text    =
JText::_('PLG_EDITORS-XTD_CONTACT_BUTTON_CONTACT');
			$button->name    = 'address';
			$button->options = "{handler: 'iframe', size: {x: 800,
y: 500}}";

			return $button;
		}
	}
}
editors-xtd/contact/contact.xml000064400000001444147357022240012633
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7" type="plugin"
group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_contact</name>
	<author>Joomla! Project</author>
	<creationDate>October 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_EDITORS-XTD_CONTACT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contact">contact.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors-xtd_contact.ini</language>
		<language
tag="en-GB">en-GB.plg_editors-xtd_contact.sys.ini</language>
	</languages>
</extension>
editors-xtd/fields/fields.php000064400000003317147357022240012251
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.fields
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Fields button
 *
 * @since  3.7.0
 */
class PlgButtonFields extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since  3.7.0
	 */
	public function onDisplay($name)
	{
		// Check if com_fields is enabled
		if (!JComponentHelper::isEnabled('com_fields'))
		{
			return;
		}

		// Register FieldsHelper
		JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR .
'/components/com_fields/helpers/fields.php');

		// Guess the field context based on view.
		$jinput = JFactory::getApplication()->input;
		$context = $jinput->get('option') . '.' .
$jinput->get('view');

		// Validate context.
		$context = implode('.', FieldsHelper::extract($context));
		if (!FieldsHelper::getFields($context))
		{
			return;
		}

		$link =
'index.php?option=com_fields&amp;view=fields&amp;layout=modal&amp;tmpl=component&amp;context='
			. $context . '&amp;editor=' . $name .
'&amp;' . JSession::getFormToken() . '=1';

		$button          = new JObject;
		$button->modal   = true;
		$button->class   = 'btn';
		$button->link    = $link;
		$button->text    =
JText::_('PLG_EDITORS-XTD_FIELDS_BUTTON_FIELD');
		$button->name    = 'puzzle';
		$button->options = "{handler: 'iframe', size: {x: 800,
y: 500}}";

		return $button;
	}
}
editors-xtd/fields/fields.xml000064400000001437147357022240012263
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7" type="plugin"
group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_fields</name>
	<author>Joomla! Project</author>
	<creationDate>February 2017</creationDate>
	<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_EDITORS-XTD_FIELDS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="fields">fields.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors-xtd_fields.ini</language>
		<language
tag="en-GB">en-GB.plg_editors-xtd_fields.sys.ini</language>
	</languages>
</extension>
editors-xtd/image/image.php000064400000004175147357022240011704
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.image
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Image buton
 *
 * @since  1.5
 */
class PlgButtonImage extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button.
	 *
	 * @param   string   $name    The name of the button to display.
	 * @param   string   $asset   The name of the asset being edited.
	 * @param   integer  $author  The id of the author owning the asset being
edited.
	 *
	 * @return  JObject  The button options as JObject or false if not allowed
	 *
	 * @since   1.5
	 */
	public function onDisplay($name, $asset, $author)
	{
		$app       = JFactory::getApplication();
		$user      = JFactory::getUser();
		$extension = $app->input->get('option');

		// For categories we check the extension (ex: component.section)
		if ($extension === 'com_categories')
		{
			$parts     = explode('.',
$app->input->get('extension', 'com_content'));
			$extension = $parts[0];
		}

		$asset = $asset !== '' ? $asset : $extension;

		if ($user->authorise('core.edit', $asset)
			|| $user->authorise('core.create', $asset)
			|| (count($user->getAuthorisedCategories($asset,
'core.create')) > 0)
			|| ($user->authorise('core.edit.own', $asset) &&
$author === $user->id)
			|| (count($user->getAuthorisedCategories($extension,
'core.edit')) > 0)
			|| (count($user->getAuthorisedCategories($extension,
'core.edit.own')) > 0 && $author === $user->id))
		{
			$link =
'index.php?option=com_media&amp;view=images&amp;tmpl=component&amp;e_name='
. $name . '&amp;asset=' . $asset .
'&amp;author=' . $author;

			$button = new JObject;
			$button->modal   = true;
			$button->class   = 'btn';
			$button->link    = $link;
			$button->text    = JText::_('PLG_IMAGE_BUTTON_IMAGE');
			$button->name    = 'pictures';
			$button->options = "{handler: 'iframe', size: {x: 800,
y: 500}}";

			return $button;
		}

		return false;
	}
}
editors-xtd/image/image.xml000064400000001413147357022240011705
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_image</name>
	<author>Joomla! Project</author>
	<creationDate>August 2004</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_IMAGE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="image">image.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors-xtd_image.ini</language>
		<language
tag="en-GB">en-GB.plg_editors-xtd_image.sys.ini</language>
	</languages>
</extension>
editors-xtd/menu/menu.php000064400000002530147357022240011441
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.menu
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor menu button
 *
 * @since  3.7.0
 */
class PlgButtonMenu extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @since  3.7.0
	 * @return array
	 */
	public function onDisplay($name)
	{
		/*
		 * Use the built-in element view to select the menu item.
		 * Currently uses blank class.
		 */
		$user  = JFactory::getUser();

		if ($user->authorise('core.create', 'com_menus')
			|| $user->authorise('core.edit', 'com_menus'))
		{
		$link =
'index.php?option=com_menus&amp;view=items&amp;layout=modal&amp;tmpl=component&amp;'
			. JSession::getFormToken() . '=1&amp;editor=' . $name;

		$button          = new JObject;
		$button->modal   = true;
		$button->class   = 'btn';
		$button->link    = $link;
		$button->text    =
JText::_('PLG_EDITORS-XTD_MENU_BUTTON_MENU');
		$button->name    = 'share-alt';
		$button->options = "{handler: 'iframe', size: {x: 800,
y: 500}}";

		return $button;
		}
	}
}
editors-xtd/menu/menu.xml000064400000001421147357022240011450
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7" type="plugin"
group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_menu</name>
	<author>Joomla! Project</author>
	<creationDate>August 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_EDITORS-XTD_MENU_XML_DESCRIPTION</description>
	<files>
		<filename plugin="menu">menu.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors-xtd_menu.ini</language>
		<language
tag="en-GB">en-GB.plg_editors-xtd_menu.sys.ini</language>
	</languages>
</extension>
editors-xtd/module/module.php000064400000002702147357022240012304
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.module
 *
 * @copyright   (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Module button
 *
 * @since  3.5
 */
class PlgButtonModule extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.5
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   3.5
	 */
	public function onDisplay($name)
	{
		/*
		 * Use the built-in element view to select the module.
		 * Currently uses blank class.
		 */
		$user  = JFactory::getUser();

		if ($user->authorise('core.create', 'com_modules')
			|| $user->authorise('core.edit', 'com_modules')
			|| $user->authorise('core.edit.own',
'com_modules'))
		{
			$link =
'index.php?option=com_modules&amp;view=modules&amp;layout=modal&amp;tmpl=component&amp;editor='
					. $name . '&amp;' . JSession::getFormToken() .
'=1';

			$button          = new JObject;
			$button->modal   = true;
			$button->class   = 'btn';
			$button->link    = $link;
			$button->text    = JText::_('PLG_MODULE_BUTTON_MODULE');
			$button->name    = 'file-add';
			$button->options = "{handler: 'iframe', size: {x: 800,
y: 500}}";

			return $button;
		}
	}
}
editors-xtd/module/module.xml000064400000001422147357022240012313
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin"
group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_module</name>
	<author>Joomla! Project</author>
	<creationDate>October 2015</creationDate>
	<copyright>(C) 2015 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.5.0</version>
	<description>PLG_MODULE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="module">module.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors-xtd_module.ini</language>
		<language
tag="en-GB">en-GB.plg_editors-xtd_module.sys.ini</language>
	</languages>
</extension>
editors-xtd/pagebreak/pagebreak.php000064400000003632147357022240013377
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.pagebreak
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Pagebreak button
 *
 * @since  1.5
 */
class PlgButtonPagebreak extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Display the button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   1.5
	 */
	public function onDisplay($name)
	{
		$input = JFactory::getApplication()->input;
		$user  = JFactory::getUser();

		// Can create in any category (component permission) or at least in one
category
		$canCreateRecords = $user->authorise('core.create',
'com_content')
			|| count($user->getAuthorisedCategories('com_content',
'core.create')) > 0;

		// Instead of checking edit on all records, we can use **same** check as
the form editing view
		$values = (array)
JFactory::getApplication()->getUserState('com_content.edit.article.id');
		$isEditingRecords = count($values);

		// This ACL check is probably a double-check (form view already performed
checks)
		$hasAccess = $canCreateRecords || $isEditingRecords;
		if (!$hasAccess)
		{
			return;
		}

		JFactory::getDocument()->addScriptOptions('xtd-pagebreak',
array('editor' => $name));
		$link =
'index.php?option=com_content&amp;view=article&amp;layout=pagebreak&amp;tmpl=component&amp;e_name='
. $name;

		$button          = new JObject;
		$button->modal   = true;
		$button->class   = 'btn';
		$button->link    = $link;
		$button->text    =
JText::_('PLG_EDITORSXTD_PAGEBREAK_BUTTON_PAGEBREAK');
		$button->name    = 'copy';
		$button->options = "{handler: 'iframe', size: {x: 500,
y: 300}}";

		return $button;
	}
}
editors-xtd/pagebreak/pagebreak.xml000064400000001456147357022240013412
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_pagebreak</name>
	<author>Joomla! Project</author>
	<creationDate>August 2004</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_EDITORSXTD_PAGEBREAK_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="pagebreak">pagebreak.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors-xtd_pagebreak.ini</language>
		<language
tag="en-GB">en-GB.plg_editors-xtd_pagebreak.sys.ini</language>
	</languages>
</extension>
editors-xtd/readmore/readmore.php000064400000002507147357022240013131
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors-xtd.readmore
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Editor Readmore button
 *
 * @since  1.5
 */
class PlgButtonReadmore extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Readmore button
	 *
	 * @param   string  $name  The name of the button to add
	 *
	 * @return  JObject  The button options as JObject
	 *
	 * @since   1.5
	 */
	public function onDisplay($name)
	{
		JHtml::_('script',
'com_content/admin-article-readmore.min.js',
array('version' => 'auto', 'relative'
=> true));

		// Pass some data to javascript
		JFactory::getDocument()->addScriptOptions(
			'xtd-readmore',
			array(
				'editor' => $this->_subject->getContent($name),
				'exists' =>
JText::_('PLG_READMORE_ALREADY_EXISTS', true),
			)
		);

		$button = new JObject;
		$button->modal   = false;
		$button->class   = 'btn';
		$button->onclick = 'insertReadmore(\'' . $name .
'\');return false;';
		$button->text    = JText::_('PLG_READMORE_BUTTON_READMORE');
		$button->name    = 'arrow-down';
		$button->link    = '#';

		return $button;
	}
}
editors-xtd/readmore/readmore.xml000064400000001434147357022240013140
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="editors-xtd" method="upgrade">
	<name>plg_editors-xtd_readmore</name>
	<author>Joomla! Project</author>
	<creationDate>March 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_READMORE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="readmore">readmore.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_editors-xtd_readmore.ini</language>
		<language
tag="en-GB">en-GB.plg_editors-xtd_readmore.sys.ini</language>
	</languages>
</extension>
extension/joomla/joomla.php000064400000016167147357022240012054
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Extension.Joomla
 *
 * @copyright   (C) 2010 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! master extension plugin.
 *
 * @since  1.6
 */
class PlgExtensionJoomla extends JPlugin
{
	/**
	 * @var    integer Extension Identifier
	 * @since  1.6
	 */
	private $eid = 0;

	/**
	 * @var    JInstaller Installer object
	 * @since  1.6
	 */
	private $installer = null;

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Adds an update site to the table if it doesn't exist.
	 *
	 * @param   string   $name        The friendly name of the site
	 * @param   string   $type        The type of site (e.g. collection or
extension)
	 * @param   string   $location    The URI for the site
	 * @param   boolean  $enabled     If this site is enabled
	 * @param   string   $extraQuery  Any additional request query to use when
updating
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	private function addUpdateSite($name, $type, $location, $enabled,
$extraQuery = '')
	{
		$db = JFactory::getDbo();

		// Look if the location is used already; doesn't matter what type
you can't have two types at the same address, doesn't make sense
		$query = $db->getQuery(true)
			->select('update_site_id')
			->from('#__update_sites')
			->where('location = ' . $db->quote($location));
		$db->setQuery($query);
		$update_site_id = (int) $db->loadResult();

		// If it doesn't exist, add it!
		if (!$update_site_id)
		{
			$query->clear()
				->insert('#__update_sites')
				->columns(
					array(
						$db->quoteName('name'),
						$db->quoteName('type'),
						$db->quoteName('location'),
						$db->quoteName('enabled'),
						$db->quoteName('extra_query')
					)
				)
				->values(
					$db->quote($name) . ', '
					. $db->quote($type) . ', '
					// Trim to remove any whitespace from the XML file before saving the
location to the db
					. $db->quote(trim($location)) . ', '
					. (int) $enabled . ', '
					. $db->quote($extraQuery)
				);
			$db->setQuery($query);

			if ($db->execute())
			{
				// Link up this extension to the update site
				$update_site_id = $db->insertid();
			}
		}

		// Check if it has an update site id (creation might have failed)
		if ($update_site_id)
		{
			// Look for an update site entry that exists
			$query->clear()
				->select('update_site_id')
				->from('#__update_sites_extensions')
				->where('update_site_id = ' . $update_site_id)
				->where('extension_id = ' . $this->eid);
			$db->setQuery($query);
			$tmpid = (int) $db->loadResult();

			if (!$tmpid)
			{
				// Link this extension to the relevant update site
				$query->clear()
					->insert('#__update_sites_extensions')
					->columns(array($db->quoteName('update_site_id'),
$db->quoteName('extension_id')))
					->values($update_site_id . ', ' . $this->eid);
				$db->setQuery($query);
				$db->execute();
			}
		}
	}

	/**
	 * Handle post extension install update sites
	 *
	 * @param   JInstaller  $installer  Installer object
	 * @param   integer     $eid        Extension Identifier
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onExtensionAfterInstall($installer, $eid)
	{
		if ($eid)
		{
			$this->installer = $installer;
			$this->eid = $eid;

			// After an install we only need to do update sites
			$this->processUpdateSites();
		}
	}

	/**
	 * Handle extension uninstall
	 *
	 * @param   JInstaller  $installer  Installer instance
	 * @param   integer     $eid        Extension id
	 * @param   boolean     $result     Installation result
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onExtensionAfterUninstall($installer, $eid, $result)
	{
		// If we have a valid extension ID and the extension was successfully
uninstalled wipe out any
		// update sites for it
		if ($eid && $result)
		{
			$db = JFactory::getDbo();
			$query = $db->getQuery(true)
				->delete('#__update_sites_extensions')
				->where('extension_id = ' . $eid);
			$db->setQuery($query);
			$db->execute();

			// Delete any unused update sites
			$query->clear()
				->select('update_site_id')
				->from('#__update_sites_extensions');
			$db->setQuery($query);
			$results = $db->loadColumn();

			if (is_array($results))
			{
				// So we need to delete the update sites and their associated updates
				$updatesite_delete = $db->getQuery(true);
				$updatesite_delete->delete('#__update_sites');
				$updatesite_query = $db->getQuery(true);
				$updatesite_query->select('update_site_id')
					->from('#__update_sites');

				// If we get results back then we can exclude them
				if (count($results))
				{
					$updatesite_query->where('update_site_id NOT IN (' .
implode(',', $results) . ')');
					$updatesite_delete->where('update_site_id NOT IN (' .
implode(',', $results) . ')');
				}

				// So let's find what update sites we're about to nuke and
remove their associated extensions
				$db->setQuery($updatesite_query);
				$update_sites_pending_delete = $db->loadColumn();

				if (is_array($update_sites_pending_delete) &&
count($update_sites_pending_delete))
				{
					// Nuke any pending updates with this site before we delete it
					// TODO: investigate alternative of using a query after the delete
below with a query and not in like above
					$query->clear()
						->delete('#__updates')
						->where('update_site_id IN (' . implode(',',
$update_sites_pending_delete) . ')');
					$db->setQuery($query);
					$db->execute();
				}

				// Note: this might wipe out the entire table if there are no
extensions linked
				$db->setQuery($updatesite_delete);
				$db->execute();
			}

			// Last but not least we wipe out any pending updates for the extension
			$query->clear()
				->delete('#__updates')
				->where('extension_id = ' . $eid);
			$db->setQuery($query);
			$db->execute();
		}
	}

	/**
	 * After update of an extension
	 *
	 * @param   JInstaller  $installer  Installer object
	 * @param   integer     $eid        Extension identifier
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onExtensionAfterUpdate($installer, $eid)
	{
		if ($eid)
		{
			$this->installer = $installer;
			$this->eid = $eid;

			// Handle any update sites
			$this->processUpdateSites();
		}
	}

	/**
	 * Processes the list of update sites for an extension.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	private function processUpdateSites()
	{
		$manifest      = $this->installer->getManifest();
		$updateservers = $manifest->updateservers;

		if ($updateservers)
		{
			$children = $updateservers->children();
		}
		else
		{
			$children = array();
		}

		if (count($children))
		{
			foreach ($children as $child)
			{
				$attrs = $child->attributes();
				$this->addUpdateSite($attrs['name'],
$attrs['type'], trim($child), true,
$this->installer->extraQuery);
			}
		}
		else
		{
			$data = trim((string) $updateservers);

			if ($data !== '')
			{
				// We have a single entry in the update server line, let us presume
this is an extension line
				$this->addUpdateSite(JText::_('PLG_EXTENSION_JOOMLA_UNKNOWN_SITE'),
'extension', $data, true);
			}
		}
	}
}
extension/joomla/joomla.xml000064400000001420147357022240012047
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="extension" method="upgrade">
	<name>plg_extension_joomla</name>
	<author>Joomla! Project</author>
	<creationDate>May 2010</creationDate>
	<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_EXTENSION_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_extension_joomla.ini</language>
		<language
tag="en-GB">en-GB.plg_extension_joomla.sys.ini</language>
	</languages>
</extension>
fields/calendar/calendar.php000064400000002361147357022240012055
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Calendar
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Calendar Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsCalendar extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child
on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm
$form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		// Set filter to user UTC
		$fieldNode->setAttribute('filter', 'USER_UTC');

		// Set field to use translated formats
		$fieldNode->setAttribute('translateformat', '1');
		$fieldNode->setAttribute('showtime',
$field->fieldparams->get('showtime', 0) ? 'true'
: 'false');

		return $fieldNode;
	}
}
fields/calendar/calendar.xml000064400000001504147357022240012064
0ustar00<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_calendar</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_CALENDAR_XML_DESCRIPTION</description>
	<files>
		<filename plugin="calendar">calendar.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_calendar.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_calendar.sys.ini</language>
	</languages>
</extension>
fields/calendar/params/calendar.xml000064400000000720147357022240013346
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="showtime"
				type="radio"
				label="PLG_FIELDS_CALENDAR_PARAMS_SHOWTIME_LABEL"
				description="PLG_FIELDS_CALENDAR_PARAMS_SHOWTIME_DESC"
				class="btn-group btn-group-yesno"
				default="0"
				filter="integer"
				>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
		</fieldset>
	</fields>
</form>
fields/calendar/tmpl/calendar.php000064400000001044147357022240013026
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Calendar
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

if (is_array($value))
{
	$value = implode(', ', $value);
}

$formatString =  $field->fieldparams->get('showtime', 0) ?
'DATE_FORMAT_LC5' : 'DATE_FORMAT_LC4';

echo htmlentities(JHtml::_('date', $value,
JText::_($formatString)));
fields/checkboxes/checkboxes.php000064400000000722147357022240012766
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Checkboxes
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldslistplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Checkboxes Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsCheckboxes extends FieldsListPlugin
{
}
fields/checkboxes/checkboxes.xml000064400000003073147357022240013001
0ustar00<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_checkboxes</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_CHECKBOXES_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="checkboxes">checkboxes.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_checkboxes.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_checkboxes.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="options"
					type="subform"
					label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_LABEL"
					description="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_DESC"
					layout="joomla.form.field.subform.repeatable-table"
					icon="list"
					multiple="true"
					>
					<form hidden="true" name="list_templates_modal"
repeat="true">
						<field
							name="name"
							type="text"
							label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_NAME_LABEL"
							size="30"
						/>

						<field
							name="value"
							type="text"
							label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_VALUE_LABEL"
							size="30"
						/>
					</form>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
fields/checkboxes/params/checkboxes.xml000064400000001373147357022240014265
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="options"
				type="subform"
				label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_LABEL"
				description="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_DESC"
				layout="joomla.form.field.subform.repeatable-table"
				icon="list"
				multiple="true"
				>
				<form hidden="true" name="list_templates_modal"
repeat="true">
					<field
						name="name"
						type="text"
						label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_NAME_LABEL"
						size="30"
					/>

					<field
						name="value"
						type="text"
						label="PLG_FIELDS_CHECKBOXES_PARAMS_OPTIONS_VALUE_LABEL"
						size="30"
					/>
				</form>
			</field>
		</fieldset>
	</fields>
</form>
fields/checkboxes/tmpl/checkboxes.php000064400000001166147357022240013745
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Checkboxes
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

$fieldValue = $field->value;

if ($fieldValue === '' || $fieldValue === null)
{
	return;
}

$fieldValue = (array) $fieldValue;
$texts      = array();
$options    = $this->getOptionsFromField($field);

foreach ($options as $value => $name)
{
	if (in_array((string) $value, $fieldValue))
	{
		$texts[] = JText::_($name);
	}
}

echo htmlentities(implode(', ', $texts));
fields/color/color.php000064400000002011147357022240010757 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Color
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Color Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsColor extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child
on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm
$form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('validate', 'color');

		return $fieldNode;
	}
}
fields/color/color.xml000064400000001430147357022240010774 0ustar00<?xml
version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_color</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_COLOR_XML_DESCRIPTION</description>
	<files>
		<filename plugin="color">color.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_color.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_color.sys.ini</language>
	</languages>
</extension>
fields/color/tmpl/color.php000064400000000623147357022240011742
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Color
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

if (is_array($value))
{
	$value = implode(', ', $value);
}

echo htmlentities($value);
fields/editor/editor.php000064400000002271147357022240011307
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Editor
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Editor Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsEditor extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child
on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm
$form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('buttons',
$field->fieldparams->get('buttons',
$this->params->get('buttons', 0)) ? 'true' :
'false');
		$fieldNode->setAttribute('hide', implode(',',
$field->fieldparams->get('hide', array())));

		return $fieldNode;
	}
}
fields/editor/editor.xml000064400000004501147357022240011316
0ustar00<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_editor</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_EDITOR_XML_DESCRIPTION</description>
	<files>
		<filename plugin="editor">editor.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_editor.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_editor.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="buttons"
					type="radio"
					label="PLG_FIELDS_EDITOR_PARAMS_SHOW_BUTTONS_LABEL"
					description="PLG_FIELDS_EDITOR_PARAMS_SHOW_BUTTONS_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="hide"
					type="plugins"
					label="PLG_FIELDS_EDITOR_PARAMS_BUTTONS_HIDE_LABEL"
					description="JGLOBAL_SELECT_SOME_OPTIONS"
					folder="editors-xtd"
					multiple="true"
				/>

				<field
					name="width"
					type="text"
					label="PLG_FIELDS_EDITOR_PARAMS_WIDTH_LABEL"
					description="PLG_FIELDS_EDITOR_PARAMS_WIDTH_DESC"
					default="100%"
					size="5"
				/>

				<field
					name="height"
					type="text"
					label="PLG_FIELDS_EDITOR_PARAMS_HEIGHT_LABEL"
					description="PLG_FIELDS_EDITOR_PARAMS_HEIGHT_DESC"
					default="250px"
					size="5"
				/>

				<field
					name="filter"
					type="list"
					label="PLG_FIELDS_EDITOR_PARAMS_FILTER_LABEL"
					description="PLG_FIELDS_EDITOR_PARAMS_FILTER_DESC"
					class="btn-group"
					default="JComponentHelper::filterText"
					validate="options"
					>
					<option value="0">JNO</option>
					<option
value="raw">JLIB_FILTER_PARAMS_RAW</option>
					<option
value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
					<option
value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
fields/editor/params/editor.xml000064400000002746147357022240012612
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="buttons"
				type="list"
				label="PLG_FIELDS_EDITOR_PARAMS_SHOW_BUTTONS_LABEL"
				description="PLG_FIELDS_EDITOR_PARAMS_SHOW_BUTTONS_DESC"
				filter="integer"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>

			<field
				name="hide"
				type="plugins"
				label="PLG_FIELDS_EDITOR_PARAMS_BUTTONS_HIDE_LABEL"
				description="JGLOBAL_SELECT_SOME_OPTIONS"
				folder="editors-xtd"
				multiple="true"
			/>

			<field
				name="width"
				type="text"
				label="PLG_FIELDS_EDITOR_PARAMS_WIDTH_LABEL"
				description="PLG_FIELDS_EDITOR_PARAMS_WIDTH_DESC"
				size="5"
			/>

			<field
				name="height"
				type="text"
				label="PLG_FIELDS_EDITOR_PARAMS_HEIGHT_LABEL"
				description="PLG_FIELDS_EDITOR_PARAMS_HEIGHT_DESC"
				size="5"
			/>

			<field
				name="filter"
				type="list"
				label="PLG_FIELDS_TEXT_PARAMS_FILTER_LABEL"
				description="PLG_FIELDS_TEXT_PARAMS_FILTER_DESC"
				class="btn-group"
				validate="options"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="0">JNO</option>
				<option
value="raw">JLIB_FILTER_PARAMS_RAW</option>
				<option
value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
				<option
value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
			</field>
		</fieldset>
	</fields>
</form>
fields/editor/tmpl/editor.php000064400000000546147357022240012266
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Editor
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

echo JHtml::_('content.prepare', $value);
fields/imagelist/imagelist.php000064400000002165147357022240012471
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Imagelist
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Imagelist Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsImagelist extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child
on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm
$form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('hide_default', 'true');
		$fieldNode->setAttribute('directory', '/images/' .
$fieldNode->getAttribute('directory'));

		return $fieldNode;
	}
}
fields/imagelist/imagelist.xml000064400000003436147357022240012504
0ustar00<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_imagelist</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_IMAGELIST_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="imagelist">imagelist.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_imagelist.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_imagelist.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="directory"
					type="folderlist"
					label="PLG_FIELDS_IMAGELIST_PARAMS_DIRECTORY_LABEL"
					description="PLG_FIELDS_IMAGELIST_PARAMS_DIRECTORY_DESC"
					directory="images"
					hide_none="true"
					hide_default="true"
					recursive="true"
					default="/"
					>
					<option value="/">/</option>
				</field>

				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_IMAGELIST_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_IMAGELIST_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="image_class"
					type="textarea"
					label="PLG_FIELDS_IMAGELIST_PARAMS_IMAGE_CLASS_LABEL"
					description="PLG_FIELDS_IMAGELIST_PARAMS_IMAGE_CLASS_DESC"
					size="40"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
fields/imagelist/params/imagelist.xml000064400000002011147357022240013753
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="directory"
				type="folderlist"
				label="PLG_FIELDS_IMAGELIST_PARAMS_DIRECTORY_LABEL"
				description="PLG_FIELDS_IMAGELIST_PARAMS_DIRECTORY_DESC"
				directory="images"
				hide_none="true"
				hide_default="true"
				recursive="true"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="/">/</option>
			</field>

			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_IMAGELIST_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_IMAGELIST_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>

			<field
				name="image_class"
				type="textarea"
				label="PLG_FIELDS_IMAGELIST_PARAMS_IMAGE_CLASS_LABEL"
				description="PLG_FIELDS_IMAGELIST_PARAMS_IMAGE_CLASS_DESC"
				size="40"
			/>
		</fieldset>
	</fields>
</form>
fields/imagelist/tmpl/imagelist.php000064400000001711147357022240013441
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Imagelist
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

if ($field->value == '')
{
	return;
}

$class = $fieldParams->get('image_class');

if ($class)
{
	// space before, so if no class sprintf below works
	$class = ' class="' . htmlentities($class, ENT_COMPAT,
'UTF-8', true) . '"';
}

$value  = (array) $field->value;
$buffer = '';

foreach ($value as $path)
{
	if (!$path || $path == '-1')
	{
		continue;
	}

	if ($fieldParams->get('directory', '/') !==
'/')
	{
		$buffer .= sprintf('<img
src="images/%s/%s"%s>',
			$fieldParams->get('directory'),
			htmlentities($path, ENT_COMPAT, 'UTF-8', true),
			$class
		);
	}
	else
	{
		$buffer .= sprintf('<img src="images/%s"%s>',
			htmlentities($path, ENT_COMPAT, 'UTF-8', true),
			$class
		);
	}
}

echo $buffer;
fields/integer/integer.php000064400000000701147357022240011621
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Integer
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Integer Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsInteger extends FieldsPlugin
{
}
fields/integer/integer.xml000064400000003564147357022240011644
0ustar00<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_integer</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_INTEGER_XML_DESCRIPTION</description>
	<files>
		<filename plugin="integer">integer.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_integer.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_integer.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_INTEGER_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_INTEGER_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="first"
					type="number"
					label="PLG_FIELDS_INTEGER_PARAMS_FIRST_LABEL"
					description="PLG_FIELDS_INTEGER_PARAMS_FIRST_DESC"
					default="1"
					filter="integer"
					size="5"
				/>

				<field
					name="last"
					type="number"
					label="PLG_FIELDS_INTEGER_PARAMS_LAST_LABEL"
					description="PLG_FIELDS_INTEGER_PARAMS_LAST_DESC"
					default="100"
					filter="integer"
					size="5"
				/>

				<field
					name="step"
					type="number"
					label="PLG_FIELDS_INTEGER_PARAMS_STEP_LABEL"
					description="PLG_FIELDS_INTEGER_PARAMS_STEP_DESC"
					default="1"
					filter="integer"
					size="5"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
fields/integer/params/integer.xml000064400000002010147357022240013110
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_INTEGER_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_INTEGER_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>

			<field
				name="first"
				type="number"
				label="PLG_FIELDS_INTEGER_PARAMS_FIRST_LABEL"
				description="PLG_FIELDS_INTEGER_PARAMS_FIRST_DESC"
				filter="integer"
				size="5"
			/>

			<field
				name="last"
				type="number"
				label="PLG_FIELDS_INTEGER_PARAMS_LAST_LABEL"
				description="PLG_FIELDS_INTEGER_PARAMS_LAST_DESC"
				filter="integer"
				size="5"
			/>

			<field
				name="step"
				type="number"
				label="PLG_FIELDS_INTEGER_PARAMS_STEP_LABEL"
				description="PLG_FIELDS_INTEGER_PARAMS_STEP_DESC"
				filter="integer"
				size="5"
			/>
		</fieldset>
	</fields>
</form>
fields/integer/tmpl/integer.php000064400000000675147357022240012607
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Integer
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

if (is_array($value))
{
	$value = implode(', ', array_map('intval', $value));
}
else
{
	$value = (int) $value;
}

echo $value;
fields/list/list.php000064400000002040147357022240010453 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.List
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldslistplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields list Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsList extends FieldsListPlugin
{
	/**
	 * Prepares the field
	 *
	 * @param   string    $context  The context.
	 * @param   stdclass  $item     The item.
	 * @param   stdclass  $field    The field.
	 *
	 * @return  object
	 *
	 * @since   3.9.2
	 */
	public function onCustomFieldsPrepareField($context, $item, $field)
	{
		// Check if the field should be processed
		if (!$this->isTypeSupported($field->type))
		{
			return;
		}

		// The field's rawvalue should be an array
		if (!is_array($field->rawvalue))
		{
			$field->rawvalue = (array) $field->rawvalue;
		}

		return parent::onCustomFieldsPrepareField($context, $item, $field);
	}
}
fields/list/list.xml000064400000003426147357022240010475 0ustar00<?xml
version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_list</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_LIST_XML_DESCRIPTION</description>
	<files>
		<filename plugin="list">list.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_list.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_list.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_LIST_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_LIST_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="options"
					type="subform"
					label="PLG_FIELDS_LIST_PARAMS_OPTIONS_LABEL"
					description="PLG_FIELDS_LIST_PARAMS_OPTIONS_DESC"
					layout="joomla.form.field.subform.repeatable-table"
					icon="list"
					multiple="true"
					>
					<form hidden="true" name="list_templates_modal"
repeat="true">
						<field
							name="name"
							type="text"
							label="PLG_FIELDS_LIST_PARAMS_OPTIONS_NAME_LABEL"
							size="30"
						/>

						<field
							name="value"
							type="text"
							label="PLG_FIELDS_LIST_PARAMS_OPTIONS_VALUE_LABEL"
							size="30"
						/>
					</form>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
fields/list/params/list.xml000064400000002043147357022240011752
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_LIST_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_LIST_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>

			<field
				name="options"
				type="subform"
				label="PLG_FIELDS_LIST_PARAMS_OPTIONS_LABEL"
				description="PLG_FIELDS_LIST_PARAMS_OPTIONS_DESC"
				layout="joomla.form.field.subform.repeatable-table"
				icon="list"
				multiple="true"
				>
				<form hidden="true" name="list_templates_modal"
repeat="true">
					<field
						name="name"
						type="text"
						label="PLG_FIELDS_LIST_PARAMS_OPTIONS_NAME_LABEL"
						size="30"
					/>

					<field
						name="value"
						type="text"
						label="PLG_FIELDS_LIST_PARAMS_OPTIONS_VALUE_LABEL"
						size="30"
					/>
				</form>
			</field>
		</fieldset>
	</fields>
</form>
fields/list/tmpl/list.php000064400000001130147357022240011426
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.List
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

$fieldValue = $field->value;

if ($fieldValue == '')
{
	return;
}

$fieldValue = (array) $fieldValue;
$texts      = array();
$options    = $this->getOptionsFromField($field);

foreach ($options as $value => $name)
{
	if (in_array((string) $value, $fieldValue))
	{
		$texts[] = JText::_($name);
	}
}


echo htmlentities(implode(', ', $texts));
fields/media/media.php000064400000002014147357022240010664 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Media
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Media Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsMedia extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child
on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm
$form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('hide_default', 'true');

		return $fieldNode;
	}
}
fields/media/media.xml000064400000003350147357022240010701 0ustar00<?xml
version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_media</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_MEDIA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="media">media.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_media.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_media.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="directory"
					type="folderlist"
					label="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_LABEL"
					description="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_DESC"
					directory="images"
					hide_none="true"
					recursive="true"
				/>

				<field
					name="preview"
					type="list"
					label="PLG_FIELDS_MEDIA_PARAMS_PREVIEW_LABEL"
					description="PLG_FIELDS_MEDIA_PARAMS_PREVIEW_DESC"
					class="btn-group"
					default="tooltip"
					>
					<option
value="tooltip">PLG_FIELDS_MEDIA_PARAMS_PREVIEW_TOOLTIP</option>
					<option
value="true">PLG_FIELDS_MEDIA_PARAMS_PREVIEW_INLINE</option>
					<option value="false">JNO</option>
				</field>

				<field
					name="image_class"
					type="textarea"
					label="PLG_FIELDS_MEDIA_PARAMS_IMAGE_CLASS_LABEL"
					description="PLG_FIELDS_MEDIA_PARAMS_IMAGE_CLASS_DESC"
					size="40"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
fields/media/params/media.xml000064400000001720147357022240012163
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="directory"
				type="folderlist"
				label="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_LABEL"
				description="PLG_FIELDS_MEDIA_PARAMS_DIRECTORY_DESC"
				directory="images"
				hide_none="true"
				recursive="true"
			/>

			<field
				name="preview"
				type="list"
				label="PLG_FIELDS_MEDIA_PARAMS_PREVIEW_LABEL"
				description="PLG_FIELDS_MEDIA_PARAMS_PREVIEW_DESC"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option
value="tooltip">PLG_FIELDS_MEDIA_PARAMS_PREVIEW_TOOLTIP</option>
				<option
value="true">PLG_FIELDS_MEDIA_PARAMS_PREVIEW_INLINE</option>
				<option value="false">JNO</option>
			</field>

			<field
				name="image_class"
				type="textarea"
				label="PLG_FIELDS_MEDIA_PARAMS_IMAGE_CLASS_LABEL"
				description="PLG_FIELDS_MEDIA_PARAMS_IMAGE_CLASS_DESC"
				size="40"
			/>
		</fieldset>
	</fields>
</form>
fields/media/tmpl/media.php000064400000001230147357022240011637
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Media
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

if ($field->value == '')
{
	return;
}

$class = $fieldParams->get('image_class');

if ($class)
{
	$class = ' class="' . htmlentities($class, ENT_COMPAT,
'UTF-8', true) . '"';
}

$value  = (array) $field->value;
$buffer = '';

foreach ($value as $path)
{
	if (!$path)
	{
		continue;
	}

	$buffer .= sprintf('<img src="%s"%s>',
		htmlentities($path, ENT_COMPAT, 'UTF-8', true),
		$class
	);
}

echo $buffer;
fields/radio/params/radio.xml000064400000001777147357022240012235
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="options"
				type="subform"
				label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_LABEL"
				description="PLG_FIELDS_RADIO_PARAMS_OPTIONS_DESC"
				layout="joomla.form.field.subform.repeatable-table"
				icon="list"
				multiple="true"
				>
				<form hidden="true" name="list_templates_modal"
repeat="true">
					<field
						name="name"
						type="text"
						label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_NAME_LABEL"
						size="30"
					/>

					<field
						name="value"
						type="text"
						label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_VALUE_LABEL"
						size="30"
					/>
				</form>
			</field>
		</fieldset>
	</fields>

	<fields name="params">
		<fieldset name="basic">
			<field
				name="class"
				type="textarea"
				label="COM_FIELDS_FIELD_CLASS_LABEL"
				description="COM_FIELDS_FIELD_CLASS_DESC"
				class="input-xxlarge"
				size="40"
				default="btn-group"
			/>
		</fieldset>
	</fields>
</form>
fields/radio/radio.php000064400000000703147357022240010725 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Radio
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldslistplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Radio Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsRadio extends FieldsListPlugin
{
}
fields/radio/radio.xml000064400000003011147357022240010731 0ustar00<?xml
version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_radio</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_RADIO_XML_DESCRIPTION</description>
	<files>
		<filename plugin="radio">radio.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_radio.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_radio.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="options"
					type="subform"
					label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_LABEL"
					description="PLG_FIELDS_RADIO_PARAMS_OPTIONS_DESC"
					layout="joomla.form.field.subform.repeatable-table"
					icon="list"
					multiple="true"
					>
					<form hidden="true" name="list_templates_modal"
repeat="true">
						<field
							name="name"
							type="text"
							label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_NAME_LABEL"
							size="30"
						/>

						<field
							name="value"
							type="text"
							label="PLG_FIELDS_RADIO_PARAMS_OPTIONS_VALUE_LABEL"
							size="30"
						/>
					</form>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
fields/radio/tmpl/radio.php000064400000001124147357022240011677
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Radio
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

$value   = (array) $value;
$texts   = array();
$options = $this->getOptionsFromField($field);

foreach ($options as $optionValue => $optionText)
{
	if (in_array((string) $optionValue, $value))
	{
		$texts[] = JText::_($optionText);
	}
}


echo htmlentities(implode(', ', $texts));
fields/repeatable/params/repeatable.xml000064400000004710147357022240014237
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="fields"
				type="subform"
				label="PLG_FIELDS_REPEATABLE_PARAMS_FIELDS_LABEL"
				description="PLG_FIELDS_REPEATABLE_PARAMS_FIELDS_DESC"
				multiple="true">
				<form>
					<fields>
						<fieldset>
							<field
								name="fieldname"
								type="text"
								label="PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_NAME_LABEL"
								description="PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_NAME_DESC"
								required="true"
							/>
							<field
								name="fieldtype"
								type="list"
								label="PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_LABEL"
								description="PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_DESC"
								>
								<option
value="editor">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_EDITOR</option>
								<option
value="media">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_MEDIA</option>
								<option
value="number">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_NUMBER</option>
								<option
value="text">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_TEXT</option>
								<option
value="textarea">PLG_FIELDS_REPEATABLE_PARAMS_FIELDNAME_TYPE_TEXTAREA</option>
							</field>
							<field
								name="fieldfilter"
								type="list"
								label="PLG_FIELDS_TEXT_PARAMS_FILTER_LABEL"
								description="PLG_FIELDS_TEXT_PARAMS_FILTER_DESC"
								class="btn-group"
								validate="options"
								showon="fieldtype!:media,number"
								>
								<option value="0">JNO</option>
								<option
									showon="fieldtype:editor,text,textarea"
									value="raw">JLIB_FILTER_PARAMS_RAW</option>
								<option
									showon="fieldtype:editor,text,textarea"
									value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
								<option
									showon="fieldtype:editor,text,textarea"
									value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
								<option
									showon="fieldtype:text,textarea"
									value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
								<option
									showon="fieldtype:text,textarea"
									value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
								<option
									showon="fieldtype:text,textarea"
									value="float">JLIB_FILTER_PARAMS_FLOAT</option>
								<option
									showon="fieldtype:text,textarea"
									value="tel">JLIB_FILTER_PARAMS_TEL</option>
							</field>
						</fieldset>
					</fields>
				</form>
			</field>
		</fieldset>
	</fields>
</form>
fields/repeatable/repeatable.php000064400000007333147357022240012747
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Repeatable
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

use Joomla\CMS\MVC\Model\BaseDatabaseModel;

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Repeatable plugin.
 *
 * @since  3.9.0
 */
class PlgFieldsRepeatable extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child
on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.9.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm
$form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$readonly = false;

		if (!FieldsHelper::canEditFieldValue($field))
		{
			$readonly = true;
		}

		$fieldNode->setAttribute('type', 'subform');
		$fieldNode->setAttribute('multiple', 'true');
		$fieldNode->setAttribute('layout',
'joomla.form.field.subform.repeatable-table');

		// Build the form source
		$fieldsXml = new SimpleXMLElement('<form/>');
		$fields    = $fieldsXml->addChild('fields');

		// Get the form settings
		$formFields = $field->fieldparams->get('fields');

		// Add the fields to the form
		foreach ($formFields as $index => $formField)
		{
			$child = $fields->addChild('field');
			$child->addAttribute('name', $formField->fieldname);
			$child->addAttribute('type', $formField->fieldtype);
			$child->addAttribute('readonly', $readonly);

			if (isset($formField->fieldfilter))
			{
				$child->addAttribute('filter',
$formField->fieldfilter);
			}
		}

		$fieldNode->setAttribute('formsource',
$fieldsXml->asXML());

		// Return the node
		return $fieldNode;
	}

	/**
	 * The save event.
	 *
	 * @param   string   $context  The context
	 * @param   JTable   $item     The article data
	 * @param   boolean  $isNew    Is new item
	 * @param   array    $data     The validated data
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentAfterSave($context, $item, $isNew, $data =
array())
	{
		// Create correct context for category
		if ($context == 'com_categories.category')
		{
			$context = $item->get('extension') .
'.categories';

			// Set the catid on the category to get only the fields which belong to
this category
			$item->set('catid', $item->get('id'));
		}

		// Check the context
		$parts = FieldsHelper::extract($context, $item);

		if (!$parts)
		{
			return true;
		}

		// Compile the right context for the fields
		$context = $parts[0] . '.' . $parts[1];

		// Loading the fields
		$fields = FieldsHelper::getFields($context, $item);

		if (!$fields)
		{
			return true;
		}

		// Get the fields data
		$fieldsData = !empty($data['com_fields']) ?
$data['com_fields'] : array();

		// Loading the model
		/** @var FieldsModelField $model */
		$model = BaseDatabaseModel::getInstance('Field',
'FieldsModel', array('ignore_request' => true));

		// Loop over the fields
		foreach ($fields as $field)
		{
			// Find the field of this type repeatable
			if ($field->type !== $this->_name)
			{
				continue;
			}

			// Determine the value if it is available from the data
			$value = key_exists($field->name, $fieldsData) ?
$fieldsData[$field->name] : null;

			// Handle json encoded values
			if (!is_array($value))
			{
				$value = json_decode($value, true);
			}

			// Setting the value for the field and the item
			$model->setFieldValue($field->id, $item->get('id'),
json_encode($value));
		}

		return true;
	}
}
fields/repeatable/repeatable.xml000064400000001556147357022240012761
0ustar00<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.8.0"
group="fields" method="upgrade">
	<name>plg_fields_repeatable</name>
	<author>Joomla! Project</author>
	<creationDate>April 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_FIELDS_REPEATABLE_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="repeatable">repeatable.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages folder="language">
		<language
tag="en-GB">en-GB/en-GB.plg_fields_repeatable.ini</language>
		<language
tag="en-GB">en-GB/en-GB.plg_fields_repeatable.sys.ini</language>
	</languages>
</extension>
fields/repeatable/tmpl/repeatable.php000064400000001077147357022240013722
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Repeatable
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

$fieldValue = $field->value;

if ($fieldValue === '')
{
	return;
}

// Get the values
$fieldValues = json_decode($fieldValue, true);

if (empty($fieldValues))
{
	return;
}

$html = '<ul>';

foreach ($fieldValues as $value)
{
	$html .= '<li>' . implode(', ', $value) .
'</li>';
}

$html .= '</ul>';

echo $html;
fields/sql/params/sql.xml000064400000001223147357022240011421
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="query"
				type="textarea"
				label="PLG_FIELDS_SQL_PARAMS_QUERY_LABEL"
				description="PLG_FIELDS_SQL_PARAMS_QUERY_DESC"
				filter="raw"
				rows="10"
				required="true"
			/>

			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_SQL_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_SQL_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
		</fieldset>
	</fields>
</form>
fields/sql/sql.php000064400000003516147357022240010134 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Sql
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldslistplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Sql Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsSql extends FieldsListPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child
on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm
$form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('value_field', 'text');
		$fieldNode->setAttribute('key_field', 'value');

		return $fieldNode;
	}

	/**
	 * The save event.
	 *
	 * @param   string   $context  The context
	 * @param   JTable   $item     The table
	 * @param   boolean  $isNew    Is new item
	 * @param   array    $data     The validated data
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onContentBeforeSave($context, $item, $isNew, $data =
array())
	{
		// Only work on new SQL fields
		if ($context != 'com_fields.field' || !isset($item->type) ||
$item->type != 'sql')
		{
			return true;
		}

		// If we are not a super admin, don't let the user create or update
a SQL field
		if (!JAccess::getAssetRules(1)->allow('core.admin',
JFactory::getUser()->getAuthorisedGroups()))
		{
			$item->setError(JText::_('PLG_FIELDS_SQL_CREATE_NOT_POSSIBLE'));

			return false;
		}

		return true;
	}
}
fields/sql/sql.xml000064400000002643147357022240010145 0ustar00<?xml
version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_sql</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_SQL_XML_DESCRIPTION</description>
	<files>
		<filename plugin="sql">sql.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_sql.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_sql.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="query"
					type="textarea"
					label="PLG_FIELDS_SQL_PARAMS_QUERY_LABEL"
					description="PLG_FIELDS_SQL_PARAMS_QUERY_DESC"
					rows="10"
					filter="raw"
					required="true"
				/>

				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_SQL_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_SQL_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
fields/sql/tmpl/sql.php000064400000001754147357022240011112
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Sql
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

$db        = JFactory::getDbo();
$value     = (array) $value;
$condition = '';

foreach ($value as $v)
{
	if (!$v)
	{
		continue;
	}

	$condition .= ', ' . $db->q($v);
}

$query = $fieldParams->get('query', '');

// Run the query with a having condition because it supports aliases
$db->setQuery($query . ' having value in (' . trim($condition,
',') . ')');

try
{
	$items = $db->loadObjectlist();
}
catch (Exception $e)
{
	// If the query failed, we fetch all elements
	$db->setQuery($query);
	$items = $db->loadObjectlist();
}

$texts = array();

foreach ($items as $item)
{
	if (in_array($item->value, $value))
	{
		$texts[] = $item->text;
	}
}

echo htmlentities(implode(', ', $texts));
fields/text/params/text.xml000064400000002055147357022240011777
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="filter"
				type="list"
				label="PLG_FIELDS_TEXT_PARAMS_FILTER_LABEL"
				description="PLG_FIELDS_TEXT_PARAMS_FILTER_DESC"
				class="btn-group"
				validate="options"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="0">JNO</option>
				<option
value="raw">JLIB_FILTER_PARAMS_RAW</option>
				<option
value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
				<option
value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
				<option
value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
				<option
value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
				<option
value="float">JLIB_FILTER_PARAMS_FLOAT</option>
				<option
value="tel">JLIB_FILTER_PARAMS_TEL</option>
			</field>

			<field
				name="maxlength"
				type="number"
				label="PLG_FIELDS_TEXT_PARAMS_MAXLENGTH_LABEL"
				description="PLG_FIELDS_TEXT_PARAMS_MAXLENGTH_DESC"
				filter="integer"
			/>
		</fieldset>
	</fields>
</form>
fields/text/text.php000064400000000670147357022240010504 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Text
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Text Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsText extends FieldsPlugin
{
}
fields/text/text.xml000064400000003473147357022240010521 0ustar00<?xml
version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_text</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_TEXT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="text">text.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_text.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_text.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="filter"
					type="list"
					label="PLG_FIELDS_TEXT_PARAMS_FILTER_LABEL"
					description="PLG_FIELDS_TEXT_PARAMS_FILTER_DESC"
					class="btn-group"
					default="JComponentHelper::filterText"
					validate="options"
					>
					<option value="0">JNO</option>
					<option
value="raw">JLIB_FILTER_PARAMS_RAW</option>
					<option
value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
					<option
value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
					<option
value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
					<option
value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
					<option
value="float">JLIB_FILTER_PARAMS_FLOAT</option>
					<option
value="tel">JLIB_FILTER_PARAMS_TEL</option>
				</field>

				<field
					name="maxlength"
					type="number"
					label="PLG_FIELDS_TEXT_PARAMS_MAXLENGTH_LABEL"
					description="PLG_FIELDS_TEXT_PARAMS_MAXLENGTH_DESC"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
fields/text/tmpl/text.php000064400000000622147357022240011455
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Text
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

if (is_array($value))
{
	$value = implode(', ', $value);
}

echo htmlentities($value);
fields/textarea/params/textarea.xml000064400000002671147357022240013465
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="rows"
				type="number"
				label="PLG_FIELDS_TEXTAREA_PARAMS_ROWS_LABEL"
				description="PLG_FIELDS_TEXTAREA_PARAMS_ROWS_DESC"
				filter="integer"
				size="5"
			/>

			<field
				name="cols"
				type="number"
				label="PLG_FIELDS_TEXTAREA_PARAMS_COLS_LABEL"
				description="PLG_FIELDS_TEXTAREA_PARAMS_COLS_DESC"
				filter="integer"
				size="5"
			/>

			<field
				name="maxlength"
				type="number"
				label="PLG_FIELDS_TEXTAREA_PARAMS_MAXLENGTH_LABEL"
				description="PLG_FIELDS_TEXTAREA_PARAMS_MAXLENGTH_DESC"
				filter="integer"
			/>

			<field
				name="filter"
				type="list"
				label="PLG_FIELDS_TEXTAREA_PARAMS_FILTER_LABEL"
				description="PLG_FIELDS_TEXTAREA_PARAMS_FILTER_DESC"
				class="btn-group"
				validate="options"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="0">JNO</option>
				<option
value="raw">JLIB_FILTER_PARAMS_RAW</option>
				<option
value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
				<option
value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
				<option
value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
				<option
value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
				<option
value="float">JLIB_FILTER_PARAMS_FLOAT</option>
				<option
value="tel">JLIB_FILTER_PARAMS_TEL</option>
			</field>
		</fieldset>
	</fields>
</form>
fields/textarea/textarea.php000064400000000704147357022240012164
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Textarea
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Textarea Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsTextarea extends FieldsPlugin
{
}
fields/textarea/textarea.xml000064400000004423147357022240012177
0ustar00<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_textarea</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_TEXTAREA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="textarea">textarea.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_textarea.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_textarea.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="rows"
					type="number"
					label="PLG_FIELDS_TEXTAREA_PARAMS_ROWS_LABEL"
					description="PLG_FIELDS_TEXTAREA_PARAMS_ROWS_DESC"
					default="10"
					filter="integer"
					size="5"
				/>

				<field
					name="cols"
					type="number"
					label="PLG_FIELDS_TEXTAREA_PARAMS_COLS_LABEL"
					description="PLG_FIELDS_TEXTAREA_PARAMS_COLS_DESC"
					default="10"
					filter="integer"
					size="5"
				/>

				<field
					name="maxlength"
					type="number"
					label="PLG_FIELDS_TEXTAREA_PARAMS_MAXLENGTH_LABEL"
					description="PLG_FIELDS_TEXTAREA_PARAMS_MAXLENGTH_DESC"
					filter="integer"
				/>

				<field
					name="filter"
					type="list"
					label="PLG_FIELDS_TEXTAREA_PARAMS_FILTER_LABEL"
					description="PLG_FIELDS_TEXTAREA_PARAMS_FILTER_DESC"
					class="btn-group"
					default="JComponentHelper::filterText"
					validate="options"
					>
					<option value="0">JNO</option>
					<option
value="raw">JLIB_FILTER_PARAMS_RAW</option>
					<option
value="safehtml">JLIB_FILTER_PARAMS_SAFEHTML</option>
					<option
value="JComponentHelper::filterText">JLIB_FILTER_PARAMS_TEXT</option>
					<option
value="alnum">JLIB_FILTER_PARAMS_ALNUM</option>
					<option
value="integer">JLIB_FILTER_PARAMS_INTEGER</option>
					<option
value="float">JLIB_FILTER_PARAMS_FLOAT</option>
					<option
value="tel">JLIB_FILTER_PARAMS_TEL</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
fields/textarea/tmpl/textarea.php000064400000000550147357022240013137
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Textarea
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

echo JHtml::_('content.prepare', $value);
fields/url/params/url.xml000064400000001560147357022240011433
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="schemes"
				type="list"
				label="PLG_FIELDS_URL_PARAMS_SCHEMES_LABEL"
				description="PLG_FIELDS_URL_PARAMS_SCHEMES_DESC"
				multiple="true"
				>
				<option value="http">HTTP</option>
				<option value="https">HTTPS</option>
				<option value="ftp">FTP</option>
				<option value="ftps">FTPS</option>
				<option value="file">FILE</option>
				<option value="mailto">MAILTO</option>
			</field>

			<field
				name="relative"
				type="list"
				label="PLG_FIELDS_URL_PARAMS_RELATIVE_LABEL"
				description="PLG_FIELDS_URL_PARAMS_RELATIVE_DESC"
				filter="integer"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
		</fieldset>
	</fields>
</form>
fields/url/tmpl/url.php000064400000001042147357022240011106
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.URL
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

$attributes = '';

if (!JUri::isInternal($value))
{
	$attributes = ' rel="nofollow noopener noreferrer"
target="_blank"';
}

echo sprintf('<a href="%s"%s>%s</a>',
	htmlspecialchars($value),
	$attributes,
	htmlspecialchars($value)
);
fields/url/url.php000064400000002144147357022240010136 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.URL
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields URL Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsUrl extends FieldsPlugin
{
	/**
	 * Transforms the field into a DOM XML element and appends it as a child
on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm
$form)
	{
		$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form);

		if (!$fieldNode)
		{
			return $fieldNode;
		}

		$fieldNode->setAttribute('validate', 'url');

		if (! $fieldNode->getAttribute('relative'))
		{
			$fieldNode->removeAttribute('relative');
		}

		return $fieldNode;
	}
}
fields/url/url.xml000064400000003205147357022240010146 0ustar00<?xml
version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_url</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_URL_XML_DESCRIPTION</description>
	<files>
		<filename plugin="url">url.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_url.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_url.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="schemes"
					type="list"
					label="PLG_FIELDS_URL_PARAMS_SCHEMES_LABEL"
					description="PLG_FIELDS_URL_PARAMS_SCHEMES_DESC"
					multiple="true"
					>
					<option value="http">HTTP</option>
					<option value="https">HTTPS</option>
					<option value="ftp">FTP</option>
					<option value="ftps">FTPS</option>
					<option value="file">FILE</option>
					<option value="mailto">MAILTO</option>
				</field>

				<field
					name="relative"
					type="radio"
					label="PLG_FIELDS_URL_PARAMS_RELATIVE_LABEL"
					description="PLG_FIELDS_URL_PARAMS_RELATIVE_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
fields/user/params/user.xml000064400000000600147357022240011755
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<field
		name="default_value"
		type="user"
		label="PLG_FIELDS_USER_DEFAULT_VALUE_LABEL"
		description="PLG_FIELDS_USER_DEFAULT_VALUE_DESC"
	/>
	<fields name="params"
label="COM_FIELDS_FIELD_BASIC_LABEL">
		<fieldset name="basic">
			<field
				name="show_on"
				type="hidden"
				filter="unset"
			/>
		</fieldset>
	</fields>
</form>
fields/user/tmpl/user.php000064400000001230147357022240011435
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.User
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

$value = (array) $value;
$texts = array();

foreach ($value as $userId)
{
	if (!$userId)
	{
		continue;
	}

	$user = JFactory::getUser($userId);

	if ($user)
	{
		// Use the Username
		$texts[] = $user->name;
		continue;
	}

	// Fallback and add the User ID if we get no JUser Object
	$texts[] = $userId;
}

echo htmlentities(implode(', ', $texts));
fields/user/user.php000064400000002004147357022240010461 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.User
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields User Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsUser extends FieldsPlugin
{

	/**
	 * Transforms the field into a DOM XML element and appends it as a child
on the given parent.
	 *
	 * @param   stdClass    $field   The field.
	 * @param   DOMElement  $parent  The field node parent.
	 * @param   JForm       $form    The form.
	 *
	 * @return  DOMElement
	 *
	 * @since   3.7.0
	 */
	public function onCustomFieldsPrepareDom($field, DOMElement $parent, JForm
$form)
	{
		if (JFactory::getApplication()->isClient('site'))
		{
			// The user field is not working on the front end
			return;
		}

		return parent::onCustomFieldsPrepareDom($field, $parent, $form);
	}
}
fields/user/user.xml000064400000001422147357022240010475 0ustar00<?xml
version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_user</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_USER_XML_DESCRIPTION</description>
	<files>
		<filename plugin="user">user.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_user.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_user.sys.ini</language>
	</languages>
</extension>
fields/usergrouplist/params/usergrouplist.xml000064400000000735147357022240015710
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="fieldparams">
		<fieldset name="fieldparams">
			<field
				name="multiple"
				type="list"
				label="PLG_FIELDS_USERGROUPLIST_PARAMS_MULTIPLE_LABEL"
				description="PLG_FIELDS_USERGROUPLIST_PARAMS_MULTIPLE_DESC"
				filter="integer"
				>
				<option
value="">COM_FIELDS_FIELD_USE_GLOBAL</option>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
		</fieldset>
	</fields>
</form>
fields/usergrouplist/tmpl/usergrouplist.php000064400000001245147357022240015365
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Usergrouplist
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

$value = $field->value;

if ($value == '')
{
	return;
}

JLoader::register('UsersHelper', JPATH_ADMINISTRATOR .
'/components/com_users/helpers/users.php');

$value  = (array) $value;
$texts  = array();
$groups = UsersHelper::getGroups();

foreach ($groups as $group)
{
	if (in_array($group->value, $value))
	{
		$texts[] = htmlentities(trim($group->text, '- '));
	}
}

echo htmlentities(implode(', ', $texts));
fields/usergrouplist/usergrouplist.php000064400000000723147357022240014411
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Fields.Usergrouplist
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::import('components.com_fields.libraries.fieldsplugin',
JPATH_ADMINISTRATOR);

/**
 * Fields Usergrouplist Plugin
 *
 * @since  3.7.0
 */
class PlgFieldsUsergrouplist extends FieldsPlugin
{
}
fields/usergrouplist/usergrouplist.xml000064400000002440147357022240014420
0ustar00<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="fields" method="upgrade">
	<name>plg_fields_usergrouplist</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_FIELDS_USERGROUPLIST_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="usergrouplist">usergrouplist.php</filename>
		<folder>params</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_fields_usergrouplist.ini</language>
		<language
tag="en-GB">en-GB.plg_fields_usergrouplist.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="multiple"
					type="radio"
					label="PLG_FIELDS_USERGROUPLIST_PARAMS_MULTIPLE_LABEL"
					description="PLG_FIELDS_USERGROUPLIST_PARAMS_MULTIPLE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
finder/categories/categories.php000064400000025202147357022240013005
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Categories
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR .
'/components/com_finder/helpers/indexer/adapter.php');

/**
 * Smart Search adapter for Joomla Categories.
 *
 * @since  2.5
 */
class PlgFinderCategories extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'Categories';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $extension = 'com_categories';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $layout = 'category';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $type_title = 'Category';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $table = '#__categories';

	/**
	 * The field the published state is stored in.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $state_field = 'published';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be
deleted
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderDelete($context, $table)
	{
		if ($context === 'com_categories.category')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove item from the index.
		return $this->remove($id);
	}

	/**
	 * Smart Search after save content method.
	 * Reindexes the link information for a category that has been saved.
	 * It also makes adjustments if the access level of the category has
changed.
	 *
	 * @param   string   $context  The context of the category passed to the
plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the category has just been created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle categories here.
		if ($context === 'com_categories.category')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the category item.
			$this->reindex($row->id);

			// Check if the parent access level is different.
			if (!$isNew && $this->old_cataccess != $row->access)
			{
				$this->categoryAccessChange($row);
			}
		}

		return true;
	}

	/**
	 * Smart Search before content save method.
	 * This event is fired before the data is actually saved.
	 *
	 * @param   string   $context  The context of the category passed to the
plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the category is just about to be
created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle categories here.
		if ($context === 'com_categories.category')
		{
			// Query the database for the old access level and the parent if the
item isn't new.
			if (!$isNew)
			{
				$this->checkItemAccess($row);
				$this->checkCategoryAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the category passed to the
plugin.
	 * @param   array    $pks      An array of primary key ids of the category
that has changed state.
	 * @param   integer  $value    The value of the state that the category
has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle categories here.
		if ($context === 'com_categories.category')
		{
			/*
			 * The category published state is tied to the parent category
			 * published state so we need to look up all published states
			 * before we change anything.
			 */
			foreach ($pks as $pk)
			{
				$query = clone $this->getStateQuery();
				$query->where('a.id = ' . (int) $pk);

				$this->db->setQuery($query);
				$item = $this->db->loadObject();

				// Translate the state.
				$state = null;

				if ($item->parent_id != 1)
				{
					$state = $item->cat_state;
				}

				$temp = $this->translateState($value, $state);

				// Update the item.
				$this->change($pk, 'state', $temp);

				// Reindex the item.
				$this->reindex($pk);
			}
		}

		// Handle when the plugin is disabled.
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a
FinderIndexerResult object.
	 * @param   string               $format  The item format.  Not used.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format =
'html')
	{
		// Check if the extension is enabled.
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		// Check if the extension that owns the category is also enabled.
		if (JComponentHelper::isEnabled($item->extension) === false)
		{
			return;
		}

		$item->setLanguage();

		$extension = ucfirst(substr($item->extension, 4));

		// Initialize the item parameters.
		$item->params = new Registry($item->params);

		$item->metadata = new Registry($item->metadata);

		/*
		 * Add the metadata processing instructions based on the category's
		 * configuration parameters.
		 */
		// Add the meta author.
		$item->metaauthor = $item->metadata->get('author');

		// Handle the link to the metadata.
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'link');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metakey');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metadesc');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metaauthor');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'author');

		// Deactivated Methods
		// $item->addInstruction(FinderIndexer::META_CONTEXT,
'created_by_alias');

		// Trigger the onContentPrepare event.
		$item->summary =
FinderIndexerHelper::prepareContent($item->summary, $item->params);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $item->extension,
$this->layout);

		$class = $extension . 'HelperRoute';

		// Need to import component route helpers dynamically, hence the reason
it's handled here.
		JLoader::register($class, JPATH_SITE . '/components/' .
$item->extension . '/helpers/route.php');

		if (class_exists($class) && method_exists($class,
'getCategoryRoute'))
		{
			$item->route = $class::getCategoryRoute($item->id,
$item->language);
		}
		else
		{
			$item->route = ContentHelperRoute::getCategoryRoute($item->id,
$item->language);
		}

		$item->path = FinderIndexerHelper::getContentPath($item->route);

		// Get the menu title if it exists.
		$title = $this->getItemMenuTitle($item->url);

		// Adjust the title if necessary.
		if (!empty($title) &&
$this->params->get('use_menu_title', true))
		{
			$item->title = $title;
		}

		// Translate the state. Categories should only be published if the parent
category is published.
		$item->state = $this->translateState($item->state);

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'Category');

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 */
	protected function setup()
	{
		// Load com_content route helper as it is the fallback for routing in the
indexer in this instance.
		JLoader::register('ContentHelperRoute', JPATH_SITE .
'/components/com_content/helpers/route.php');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query :
$db->getQuery(true)
			->select('a.id, a.title, a.alias, a.description AS summary,
a.extension')
			->select('a.created_user_id AS created_by, a.modified_time AS
modified, a.modified_user_id AS modified_by')
			->select('a.metakey, a.metadesc, a.metadata, a.language, a.lft,
a.parent_id, a.level')
			->select('a.created_time AS start_date, a.published AS state,
a.access, a.params');

		// Handle the alias CASE WHEN portion of the query.
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias',
'!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id,
'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias)
			->from('#__categories AS a')
			->where($db->quoteName('a.id') . ' > 1');

		return $query;
	}

	/**
	 * Method to get a SQL query to load the published and access states for
	 * a category and its parents.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getStateQuery()
	{
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName('a.id'))
			->select($this->db->quoteName('a.parent_id'))
			->select('a.' . $this->state_field . ' AS state,
c.published AS cat_state')
			->select('a.access, c.access AS cat_access')
			->from($this->db->quoteName('#__categories') . '
AS a')
			->join('LEFT', '#__categories AS c ON c.id =
a.parent_id');

		return $query;
	}
}
finder/categories/categories.xml000064400000001472147357022240013021
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="finder" method="upgrade">
	<name>plg_finder_categories</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_CATEGORIES_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="categories">categories.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_categories.ini</language>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_categories.sys.ini</language>
	</languages>
</extension>
finder/contacts/contacts.php000064400000030067147357022240012174
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Contacts
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR .
'/components/com_finder/helpers/indexer/adapter.php');

/**
 * Finder adapter for Joomla Contacts.
 *
 * @since  2.5
 */
class PlgFinderContacts extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'Contacts';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $extension = 'com_contact';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $layout = 'contact';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $type_title = 'Contact';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $table = '#__contact_details';

	/**
	 * The field the published state is stored in.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $state_field = 'published';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method to update the item link information when the item category is
	 * changed. This is fired when the item category is published or
unpublished
	 * from the list view.
	 *
	 * @param   string   $extension  The extension whose category has been
updated.
	 * @param   array    $pks        A list of primary key ids of the content
that has changed state.
	 * @param   integer  $value      The value of the state that the content
has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderCategoryChangeState($extension, $pks, $value)
	{
		// Make sure we're handling com_contact categories
		if ($extension === 'com_contact')
		{
			$this->categoryStateChange($pks, $value);
		}
	}

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * This event will fire when contacts are deleted and when an indexed item
is deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be
deleted
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterDelete($context, $table)
	{
		if ($context === 'com_contact.contact')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove the items.
		return $this->remove($id);
	}

	/**
	 * Method to determine if the access level of an item changed.
	 *
	 * @param   string   $context  The context of the content passed to the
plugin.
	 * @param   JTable   $row      A JTable object
	 * @param   boolean  $isNew    If the content has just been created
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle contacts here
		if ($context === 'com_contact.contact')
		{
			// Check if the access levels are different
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the item
			$this->reindex($row->id);
		}

		// Check for access changes in the category
		if ($context === 'com_categories.category')
		{
			// Check if the access levels are different
			if (!$isNew && $this->old_cataccess != $row->access)
			{
				$this->categoryAccessChange($row);
			}
		}

		return true;
	}

	/**
	 * Method to reindex the link information for an item that has been saved.
	 * This event is fired before the data is actually saved so we are going
	 * to queue the item to be indexed later.
	 *
	 * @param   string   $context  The context of the content passed to the
plugin.
	 * @param   JTable   $row      A JTable object
	 * @param   boolean  $isNew    If the content is just about to be created
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle contacts here
		if ($context === 'com_contact.contact')
		{
			// Query the database for the old access level if the item isn't
new
			if (!$isNew)
			{
				$this->checkItemAccess($row);
			}
		}

		// Check for access levels from the category
		if ($context === 'com_categories.category')
		{
			// Query the database for the old access level if the item isn't
new
			if (!$isNew)
			{
				$this->checkCategoryAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the
plugin.
	 * @param   array    $pks      A list of primary key ids of the content
that has changed state.
	 * @param   integer  $value    The value of the state that the content has
been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle contacts here
		if ($context === 'com_contact.contact')
		{
			$this->itemStateChange($pks, $value);
		}

		// Handle when the plugin is disabled
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a
FinderIndexerResult object.
	 * @param   string               $format  The item format
	 *
	 * @return  void
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format =
'html')
	{
		// Check if the extension is enabled
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		$item->setLanguage();

		// Initialize the item parameters.
		$item->params = new Registry($item->params);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $this->extension,
$this->layout);
		$item->route = ContactHelperRoute::getContactRoute($item->slug,
$item->catslug, $item->language);
		$item->path = FinderIndexerHelper::getContentPath($item->route);

		// Get the menu title if it exists.
		$title = $this->getItemMenuTitle($item->url);

		// Adjust the title if necessary.
		if (!empty($title) &&
$this->params->get('use_menu_title', true))
		{
			$item->title = $title;
		}

		/*
		 * Add the metadata processing instructions based on the contact
		 * configuration parameters.
		 */
		// Handle the contact position.
		if ($item->params->get('show_position', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT,
'position');
		}

		// Handle the contact street address.
		if ($item->params->get('show_street_address', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT,
'address');
		}

		// Handle the contact city.
		if ($item->params->get('show_suburb', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'city');
		}

		// Handle the contact region.
		if ($item->params->get('show_state', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT,
'region');
		}

		// Handle the contact country.
		if ($item->params->get('show_country', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT,
'country');
		}

		// Handle the contact zip code.
		if ($item->params->get('show_postcode', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'zip');
		}

		// Handle the contact telephone number.
		if ($item->params->get('show_telephone', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT,
'telephone');
		}

		// Handle the contact fax number.
		if ($item->params->get('show_fax', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT, 'fax');
		}

		// Handle the contact email address.
		if ($item->params->get('show_email', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT,
'email');
		}

		// Handle the contact mobile number.
		if ($item->params->get('show_mobile', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT,
'mobile');
		}

		// Handle the contact webpage.
		if ($item->params->get('show_webpage', true))
		{
			$item->addInstruction(FinderIndexer::META_CONTEXT,
'webpage');
		}

		// Handle the contact user name.
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'user');

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'Contact');

		// Add the category taxonomy data.
		$item->addTaxonomy('Category', $item->category,
$item->cat_state, $item->cat_access);

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Add the region taxonomy data.
		if (!empty($item->region) &&
$this->params->get('tax_add_region', true))
		{
			$item->addTaxonomy('Region', $item->region);
		}

		// Add the country taxonomy data.
		if (!empty($item->country) &&
$this->params->get('tax_add_country', true))
		{
			$item->addTaxonomy('Country', $item->country);
		}

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 */
	protected function setup()
	{
		// Load dependent classes.
		JLoader::register('ContactHelperRoute', JPATH_SITE .
'/components/com_contact/helpers/route.php');

		// This is a hack to get around the lack of a route helper.
		FinderIndexerHelper::getContentPath('index.php?option=com_contact');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query :
$db->getQuery(true)
			->select('a.id, a.name AS title, a.alias, a.con_position AS
position, a.address, a.created AS start_date')
			->select('a.created_by_alias, a.modified, a.modified_by')
			->select('a.metakey, a.metadesc, a.metadata, a.language')
			->select('a.sortname1, a.sortname2, a.sortname3')
			->select('a.publish_up AS publish_start_date, a.publish_down AS
publish_end_date')
			->select('a.suburb AS city, a.state AS region, a.country,
a.postcode AS zip')
			->select('a.telephone, a.fax, a.misc AS summary, a.email_to AS
email, a.mobile')
			->select('a.webpage, a.access, a.published AS state, a.ordering,
a.params, a.catid')
			->select('c.title AS category, c.published AS cat_state,
c.access AS cat_access');

		// Handle the alias CASE WHEN portion of the query
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias',
'!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id,
'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias);

		$case_when_category_alias = ' CASE WHEN ';
		$case_when_category_alias .= $query->charLength('c.alias',
'!=', '0');
		$case_when_category_alias .= ' THEN ';
		$c_id = $query->castAsChar('c.id');
		$case_when_category_alias .= $query->concatenate(array($c_id,
'c.alias'), ':');
		$case_when_category_alias .= ' ELSE ';
		$case_when_category_alias .= $c_id . ' END as catslug';
		$query->select($case_when_category_alias)

			->select('u.name')
			->from('#__contact_details AS a')
			->join('LEFT', '#__categories AS c ON c.id =
a.catid')
			->join('LEFT', '#__users AS u ON u.id =
a.user_id');

		return $query;
	}
}
finder/contacts/contacts.xml000064400000001456147357022240012205
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="finder" method="upgrade">
	<name>plg_finder_contacts</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_CONTACTS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contacts">contacts.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_contacts.ini</language>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_contacts.sys.ini</language>
	</languages>
</extension>
finder/content/content.php000064400000025400147357022240011657
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Content
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR .
'/components/com_finder/helpers/indexer/adapter.php');

/**
 * Smart Search adapter for com_content.
 *
 * @since  2.5
 */
class PlgFinderContent extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'Content';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $extension = 'com_content';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $layout = 'article';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $type_title = 'Article';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $table = '#__content';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method to update the item link information when the item category is
	 * changed. This is fired when the item category is published or
unpublished
	 * from the list view.
	 *
	 * @param   string   $extension  The extension whose category has been
updated.
	 * @param   array    $pks        A list of primary key ids of the content
that has changed state.
	 * @param   integer  $value      The value of the state that the content
has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderCategoryChangeState($extension, $pks, $value)
	{
		// Make sure we're handling com_content categories.
		if ($extension === 'com_content')
		{
			$this->categoryStateChange($pks, $value);
		}
	}

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be
deleted
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterDelete($context, $table)
	{
		if ($context === 'com_content.article')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove item from the index.
		return $this->remove($id);
	}

	/**
	 * Smart Search after save content method.
	 * Reindexes the link information for an article that has been saved.
	 * It also makes adjustments if the access level of an item or the
	 * category to which it belongs has changed.
	 *
	 * @param   string   $context  The context of the content passed to the
plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the content has just been created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle articles here.
		if ($context === 'com_content.article' || $context ===
'com_content.form')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the item.
			$this->reindex($row->id);
		}

		// Check for access changes in the category.
		if ($context === 'com_categories.category')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_cataccess != $row->access)
			{
				$this->categoryAccessChange($row);
			}
		}

		return true;
	}

	/**
	 * Smart Search before content save method.
	 * This event is fired before the data is actually saved.
	 *
	 * @param   string   $context  The context of the content passed to the
plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    If the content is just about to be created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle articles here.
		if ($context === 'com_content.article' || $context ===
'com_content.form')
		{
			// Query the database for the old access level if the item isn't
new.
			if (!$isNew)
			{
				$this->checkItemAccess($row);
			}
		}

		// Check for access levels from the category.
		if ($context === 'com_categories.category')
		{
			// Query the database for the old access level if the item isn't
new.
			if (!$isNew)
			{
				$this->checkCategoryAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the
plugin.
	 * @param   array    $pks      An array of primary key ids of the content
that has changed state.
	 * @param   integer  $value    The value of the state that the content has
been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle articles here.
		if ($context === 'com_content.article' || $context ===
'com_content.form')
		{
			$this->itemStateChange($pks, $value);
		}

		// Handle when the plugin is disabled.
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a
FinderIndexerResult object.
	 * @param   string               $format  The item format.  Not used.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format =
'html')
	{
		$item->setLanguage();

		// Check if the extension is enabled.
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		$item->context = 'com_content.article';

		// Initialise the item parameters.
		$registry = new Registry($item->params);
		$item->params = clone
JComponentHelper::getParams('com_content', true);
		$item->params->merge($registry);

		$item->metadata = new Registry($item->metadata);

		// Trigger the onContentPrepare event.
		$item->summary =
FinderIndexerHelper::prepareContent($item->summary, $item->params,
$item);
		$item->body    = FinderIndexerHelper::prepareContent($item->body,
$item->params, $item);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $this->extension,
$this->layout);
		$item->route = ContentHelperRoute::getArticleRoute($item->slug,
$item->catid, $item->language);
		$item->path = FinderIndexerHelper::getContentPath($item->route);

		// Get the menu title if it exists.
		$title = $this->getItemMenuTitle($item->url);

		// Adjust the title if necessary.
		if (!empty($title) &&
$this->params->get('use_menu_title', true))
		{
			$item->title = $title;
		}

		// Add the meta author.
		$item->metaauthor = $item->metadata->get('author');

		// Add the metadata processing instructions.
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metakey');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metadesc');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metaauthor');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'author');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'created_by_alias');

		// Translate the state. Articles should only be published if the category
is published.
		$item->state = $this->translateState($item->state,
$item->cat_state);

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'Article');

		// Add the author taxonomy data.
		if (!empty($item->author) || !empty($item->created_by_alias))
		{
			$item->addTaxonomy('Author',
!empty($item->created_by_alias) ? $item->created_by_alias :
$item->author);
		}

		// Add the category taxonomy data.
		$item->addTaxonomy('Category', $item->category,
$item->cat_state, $item->cat_access);

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 */
	protected function setup()
	{
		// Load dependent classes.
		JLoader::register('ContentHelperRoute', JPATH_SITE .
'/components/com_content/helpers/route.php');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query :
$db->getQuery(true)
			->select('a.id, a.title, a.alias, a.introtext AS summary,
a.fulltext AS body')
			->select('a.images')
			->select('a.state, a.catid, a.created AS start_date,
a.created_by')
			->select('a.created_by_alias, a.modified, a.modified_by,
a.attribs AS params')
			->select('a.metakey, a.metadesc, a.metadata, a.language,
a.access, a.version, a.ordering')
			->select('a.publish_up AS publish_start_date, a.publish_down AS
publish_end_date')
			->select('c.title AS category, c.published AS cat_state,
c.access AS cat_access');

		// Handle the alias CASE WHEN portion of the query
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias',
'!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id,
'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias);

		$case_when_category_alias = ' CASE WHEN ';
		$case_when_category_alias .= $query->charLength('c.alias',
'!=', '0');
		$case_when_category_alias .= ' THEN ';
		$c_id = $query->castAsChar('c.id');
		$case_when_category_alias .= $query->concatenate(array($c_id,
'c.alias'), ':');
		$case_when_category_alias .= ' ELSE ';
		$case_when_category_alias .= $c_id . ' END as catslug';
		$query->select($case_when_category_alias)

			->select('u.name AS author')
			->from('#__content AS a')
			->join('LEFT', '#__categories AS c ON c.id =
a.catid')
			->join('LEFT', '#__users AS u ON u.id =
a.created_by');

		return $query;
	}
}
finder/content/content.xml000064400000001450147357022240011667
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="finder" method="upgrade">
	<name>plg_finder_content</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_CONTENT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="content">content.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_content.ini</language>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_content.sys.ini</language>
	</languages>
</extension>
finder/newsfeeds/newsfeeds.php000064400000023656147357022240012514
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Newsfeeds
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR .
'/components/com_finder/helpers/indexer/adapter.php');

/**
 * Smart Search adapter for Joomla Newsfeeds.
 *
 * @since  2.5
 */
class PlgFinderNewsfeeds extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $context = 'Newsfeeds';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $extension = 'com_newsfeeds';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $layout = 'newsfeed';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $type_title = 'News Feed';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $table = '#__newsfeeds';

	/**
	 * The field the published state is stored in.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $state_field = 'published';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method to update the item link information when the item category is
	 * changed. This is fired when the item category is published or
unpublished
	 * from the list view.
	 *
	 * @param   string   $extension  The extension whose category has been
updated.
	 * @param   array    $pks        An array of primary key ids of the
content that has changed state.
	 * @param   integer  $value      The value of the state that the content
has been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderCategoryChangeState($extension, $pks, $value)
	{
		// Make sure we're handling com_newsfeeds categories.
		if ($extension === 'com_newsfeeds')
		{
			$this->categoryStateChange($pks, $value);
		}
	}

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be
deleted.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterDelete($context, $table)
	{
		if ($context === 'com_newsfeeds.newsfeed')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove the item from the index.
		return $this->remove($id);
	}

	/**
	 * Smart Search after save content method.
	 * Reindexes the link information for a newsfeed that has been saved.
	 * It also makes adjustments if the access level of a newsfeed item or
	 * the category to which it belongs has been changed.
	 *
	 * @param   string   $context  The context of the content passed to the
plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the content has just been created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle newsfeeds here.
		if ($context === 'com_newsfeeds.newsfeed')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the item.
			$this->reindex($row->id);
		}

		// Check for access changes in the category.
		if ($context === 'com_categories.category')
		{
			// Check if the access levels are different.
			if (!$isNew && $this->old_cataccess != $row->access)
			{
				$this->categoryAccessChange($row);
			}
		}

		return true;
	}

	/**
	 * Smart Search before content save method.
	 * This event is fired before the data is actually saved.
	 *
	 * @param   string   $context  The context of the content passed to the
plugin.
	 * @param   JTable   $row      A JTable object.
	 * @param   boolean  $isNew    True if the content is just about to be
created.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle newsfeeds here.
		if ($context === 'com_newsfeeds.newsfeed')
		{
			// Query the database for the old access level if the item isn't
new.
			if (!$isNew)
			{
				$this->checkItemAccess($row);
			}
		}

		// Check for access levels from the category.
		if ($context === 'com_categories.category')
		{
			// Query the database for the old access level if the item isn't
new.
			if (!$isNew)
			{
				$this->checkCategoryAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the
plugin.
	 * @param   array    $pks      An array of primary key ids of the content
that has changed state.
	 * @param   integer  $value    The value of the state that the content has
been changed to.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle newsfeeds here.
		if ($context === 'com_newsfeeds.newsfeed')
		{
			$this->itemStateChange($pks, $value);
		}

		// Handle when the plugin is disabled.
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a
FinderIndexerResult object.
	 * @param   string               $format  The item format.  Not used.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format =
'html')
	{
		// Check if the extension is enabled.
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		$item->setLanguage();

		// Initialize the item parameters.
		$item->params = new Registry($item->params);

		$item->metadata = new Registry($item->metadata);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $this->extension,
$this->layout);
		$item->route = NewsfeedsHelperRoute::getNewsfeedRoute($item->slug,
$item->catslug, $item->language);
		$item->path = FinderIndexerHelper::getContentPath($item->route);

		/*
		 * Add the metadata processing instructions based on the newsfeeds
		 * configuration parameters.
		 */
		// Add the meta author.
		$item->metaauthor = $item->metadata->get('author');

		// Handle the link to the metadata.
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'link');

		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metakey');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metadesc');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metaauthor');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'author');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'created_by_alias');

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'News Feed');

		// Add the category taxonomy data.
		$item->addTaxonomy('Category', $item->category,
$item->cat_state, $item->cat_access);

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   2.5
	 */
	protected function setup()
	{
		// Load dependent classes.
		JLoader::register('NewsfeedsHelperRoute', JPATH_SITE .
'/components/com_newsfeeds/helpers/route.php');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   2.5
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query :
$db->getQuery(true)
			->select('a.id, a.catid, a.name AS title, a.alias, a.link AS
link')
			->select('a.published AS state, a.ordering, a.created AS
start_date, a.params, a.access')
			->select('a.publish_up AS publish_start_date, a.publish_down AS
publish_end_date')
			->select('a.metakey, a.metadesc, a.metadata, a.language')
			->select('a.created_by, a.created_by_alias, a.modified,
a.modified_by')
			->select('c.title AS category, c.published AS cat_state,
c.access AS cat_access');

		// Handle the alias CASE WHEN portion of the query.
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias',
'!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id,
'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias);

		$case_when_category_alias = ' CASE WHEN ';
		$case_when_category_alias .= $query->charLength('c.alias',
'!=', '0');
		$case_when_category_alias .= ' THEN ';
		$c_id = $query->castAsChar('c.id');
		$case_when_category_alias .= $query->concatenate(array($c_id,
'c.alias'), ':');
		$case_when_category_alias .= ' ELSE ';
		$case_when_category_alias .= $c_id . ' END as catslug';
		$query->select($case_when_category_alias)

			->from('#__newsfeeds AS a')
			->join('LEFT', '#__categories AS c ON c.id =
a.catid');

		return $query;
	}
}
finder/newsfeeds/newsfeeds.xml000064400000001464147357022240012516
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="finder" method="upgrade">
	<name>plg_finder_newsfeeds</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_NEWSFEEDS_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="newsfeeds">newsfeeds.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_newsfeeds.ini</language>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_newsfeeds.sys.ini</language>
	</languages>
</extension>
finder/tags/tags.php000064400000022465147357022240010437 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Finder.Tags
 *
 * @copyright   (C) 2013 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;

JLoader::register('FinderIndexerAdapter', JPATH_ADMINISTRATOR .
'/components/com_finder/helpers/indexer/adapter.php');

/**
 * Finder adapter for Joomla Tag.
 *
 * @since  3.1
 */
class PlgFinderTags extends FinderIndexerAdapter
{
	/**
	 * The plugin identifier.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $context = 'Tags';

	/**
	 * The extension name.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $extension = 'com_tags';

	/**
	 * The sublayout to use when rendering the results.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $layout = 'tag';

	/**
	 * The type of content that the adapter indexes.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $type_title = 'Tag';

	/**
	 * The table name.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $table = '#__tags';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * The field the published state is stored in.
	 *
	 * @var    string
	 * @since  3.1
	 */
	protected $state_field = 'published';

	/**
	 * Method to remove the link information for items that have been deleted.
	 *
	 * @param   string  $context  The context of the action being performed.
	 * @param   JTable  $table    A JTable object containing the record to be
deleted
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   3.1
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterDelete($context, $table)
	{
		if ($context === 'com_tags.tag')
		{
			$id = $table->id;
		}
		elseif ($context === 'com_finder.index')
		{
			$id = $table->link_id;
		}
		else
		{
			return true;
		}

		// Remove the items.
		return $this->remove($id);
	}

	/**
	 * Method to determine if the access level of an item changed.
	 *
	 * @param   string   $context  The context of the content passed to the
plugin.
	 * @param   JTable   $row      A JTable object
	 * @param   boolean  $isNew    If the content has just been created
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   3.1
	 * @throws  Exception on database error.
	 */
	public function onFinderAfterSave($context, $row, $isNew)
	{
		// We only want to handle tags here.
		if ($context === 'com_tags.tag')
		{
			// Check if the access levels are different
			if (!$isNew && $this->old_access != $row->access)
			{
				// Process the change.
				$this->itemAccessChange($row);
			}

			// Reindex the item
			$this->reindex($row->id);
		}

		return true;
	}

	/**
	 * Method to reindex the link information for an item that has been saved.
	 * This event is fired before the data is actually saved so we are going
	 * to queue the item to be indexed later.
	 *
	 * @param   string   $context  The context of the content passed to the
plugin.
	 * @param   JTable   $row      A JTable object
	 * @param   boolean  $isNew    If the content is just about to be created
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   3.1
	 * @throws  Exception on database error.
	 */
	public function onFinderBeforeSave($context, $row, $isNew)
	{
		// We only want to handle news feeds here
		if ($context === 'com_tags.tag')
		{
			// Query the database for the old access level if the item isn't
new
			if (!$isNew)
			{
				$this->checkItemAccess($row);
			}
		}

		return true;
	}

	/**
	 * Method to update the link information for items that have been changed
	 * from outside the edit screen. This is fired when the item is published,
	 * unpublished, archived, or unarchived from the list view.
	 *
	 * @param   string   $context  The context for the content passed to the
plugin.
	 * @param   array    $pks      A list of primary key ids of the content
that has changed state.
	 * @param   integer  $value    The value of the state that the content has
been changed to.
	 *
	 * @return  void
	 *
	 * @since   3.1
	 */
	public function onFinderChangeState($context, $pks, $value)
	{
		// We only want to handle tags here
		if ($context === 'com_tags.tag')
		{
			$this->itemStateChange($pks, $value);
		}

		// Handle when the plugin is disabled
		if ($context === 'com_plugins.plugin' && $value === 0)
		{
			$this->pluginDisable($pks);
		}
	}

	/**
	 * Method to index an item. The item must be a FinderIndexerResult object.
	 *
	 * @param   FinderIndexerResult  $item    The item to index as a
FinderIndexerResult object.
	 * @param   string               $format  The item format
	 *
	 * @return  void
	 *
	 * @since   3.1
	 * @throws  Exception on database error.
	 */
	protected function index(FinderIndexerResult $item, $format =
'html')
	{
		// Check if the extension is enabled
		if (JComponentHelper::isEnabled($this->extension) === false)
		{
			return;
		}

		$item->setLanguage();

		// Initialize the item parameters.
		$registry = new Registry($item->params);
		$item->params = clone
JComponentHelper::getParams('com_tags', true);
		$item->params->merge($registry);

		$item->metadata = new Registry($item->metadata);

		// Build the necessary route and path information.
		$item->url = $this->getUrl($item->id, $this->extension,
$this->layout);
		$item->route = TagsHelperRoute::getTagRoute($item->slug);
		$item->path = FinderIndexerHelper::getContentPath($item->route);

		// Get the menu title if it exists.
		$title = $this->getItemMenuTitle($item->url);

		// Adjust the title if necessary.
		if (!empty($title) &&
$this->params->get('use_menu_title', true))
		{
			$item->title = $title;
		}

		// Add the meta author.
		$item->metaauthor = $item->metadata->get('author');

		// Handle the link to the metadata.
		$item->addInstruction(FinderIndexer::META_CONTEXT, 'link');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metakey');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metadesc');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'metaauthor');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'author');
		$item->addInstruction(FinderIndexer::META_CONTEXT,
'created_by_alias');

		// Add the type taxonomy data.
		$item->addTaxonomy('Type', 'Tag');

		// Add the author taxonomy data.
		if (!empty($item->author) || !empty($item->created_by_alias))
		{
			$item->addTaxonomy('Author',
!empty($item->created_by_alias) ? $item->created_by_alias :
$item->author);
		}

		// Add the language taxonomy data.
		$item->addTaxonomy('Language', $item->language);

		// Get content extras.
		FinderIndexerHelper::getContentExtras($item);

		// Index the item.
		$this->indexer->index($item);
	}

	/**
	 * Method to setup the indexer to be run.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   3.1
	 */
	protected function setup()
	{
		// Load dependent classes.
		JLoader::register('TagsHelperRoute', JPATH_SITE .
'/components/com_tags/helpers/route.php');

		return true;
	}

	/**
	 * Method to get the SQL query used to retrieve the list of content items.
	 *
	 * @param   mixed  $query  A JDatabaseQuery object or null.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   3.1
	 */
	protected function getListQuery($query = null)
	{
		$db = JFactory::getDbo();

		// Check if we can use the supplied SQL query.
		$query = $query instanceof JDatabaseQuery ? $query :
$db->getQuery(true)
			->select('a.id, a.title, a.alias, a.description AS
summary')
			->select('a.created_time AS start_date, a.created_user_id AS
created_by')
			->select('a.metakey, a.metadesc, a.metadata, a.language,
a.access')
			->select('a.modified_time AS modified, a.modified_user_id AS
modified_by')
			->select('a.published AS state, a.access, a.created_time AS
start_date, a.params');

		// Handle the alias CASE WHEN portion of the query
		$case_when_item_alias = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias',
'!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id,
'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias)
			->from('#__tags AS a');

		// Join the #__users table
		$query->select('u.name AS author')
			->join('LEFT', '#__users AS u ON u.id =
a.created_user_id');

		// Exclude the ROOT item
		$query->where($db->quoteName('a.id') . ' >
1');

		return $query;
	}

	/**
	 * Method to get a SQL query to load the published and access states for
the given tag.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   3.1
	 */
	protected function getStateQuery()
	{
		$query = $this->db->getQuery(true);
		$query->select($this->db->quoteName('a.id'))
			->select($this->db->quoteName('a.' .
$this->state_field, 'state') . ', ' .
$this->db->quoteName('a.access'))
			->select('NULL AS cat_state, NULL AS cat_access')
			->from($this->db->quoteName($this->table, 'a'));

		return $query;
	}

	/**
	 * Method to get the query clause for getting items to update by time.
	 *
	 * @param   string  $time  The modified timestamp.
	 *
	 * @return  JDatabaseQuery  A database object.
	 *
	 * @since   3.1
	 */
	protected function getUpdateQueryByTime($time)
	{
		// Build an SQL query based on the modified time.
		$query = $this->db->getQuery(true)
			->where('a.date >= ' . $this->db->quote($time));

		return $query;
	}
}
finder/tags/tags.xml000064400000001430147357022240010435 0ustar00<?xml
version="1.0" encoding="UTF-8"?>
<extension version="3.1" type="plugin"
group="finder" method="upgrade">
	<name>plg_finder_tags</name>
	<author>Joomla! Project</author>
	<creationDate>February 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_FINDER_TAGS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="tags">tags.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_tags.ini</language>
		<language
tag="en-GB">language/en-GB/en-GB.plg_finder_tags.sys.ini</language>
	</languages>
</extension>
index.html000064400000000037147357022240006547 0ustar00<!DOCTYPE
html><title></title>
installer/folderinstaller/folderinstaller.php000064400000001742147357022240015646
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.folderInstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

/**
 * FolderInstaller Plugin.
 *
 * @since  3.6.0
 */
class PlgInstallerFolderInstaller extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.6.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Textfield or Form of the Plugin.
	 *
	 * @return  array  Returns an array with the tab information
	 *
	 * @since   3.6.0
	 */
	public function onInstallerAddInstallationTab()
	{
		$tab            = array();
		$tab['name']    = 'folder';
		$tab['label']   =
JText::_('PLG_INSTALLER_FOLDERINSTALLER_TEXT');

		// Render the input
		ob_start();
		include JPluginHelper::getLayoutPath('installer',
'folderinstaller');
		$tab['content'] = ob_get_clean();

		return $tab;
	}
}
installer/folderinstaller/folderinstaller.xml000064400000001476147357022240015663
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin"
group="installer">
	<name>PLG_INSTALLER_FOLDERINSTALLER</name>
	<author>Joomla! Project</author>
	<creationDate>May 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.6.0</version>
	<description>PLG_INSTALLER_FOLDERINSTALLER_PLUGIN_XML_DESCRIPTION</description>

	<files>
		<filename
plugin="folderinstaller">folderinstaller.php</filename>
	</files>

	<languages>
		<language
tag="en-GB">en-GB.plg_installer_folderinstaller.ini</language>
		<language
tag="en-GB">en-GB.plg_installer_folderinstaller.sys.ini</language>
	</languages>
</extension>
installer/folderinstaller/tmpl/default.php000064400000002665147357022240015062
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.folderinstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('bootstrap.tooltip');

$app = JFactory::getApplication('administrator');

JFactory::getDocument()->addScriptDeclaration('
	Joomla.submitbuttonfolder = function()
	{
		var form = document.getElementById("adminForm");

		// do field validation 
		if (form.install_directory.value == "")
		{
			alert("' .
JText::_('PLG_INSTALLER_FOLDERINSTALLER_NO_INSTALL_PATH', true) .
'");
		}
		else
		{
			JoomlaInstaller.showLoading();
			form.installtype.value = "folder"
			form.submit();
		}
	};
');
?>
<legend><?php echo
JText::_('PLG_INSTALLER_FOLDERINSTALLER_TEXT');
?></legend>
<div class="control-group">
	<label for="install_directory"
class="control-label"><?php echo
JText::_('PLG_INSTALLER_FOLDERINSTALLER_TEXT');
?></label>
	<div class="controls">
		<input type="text" id="install_directory"
name="install_directory" class="span5 input_box"
size="70"
			value="<?php echo
$app->input->get('install_directory',
$app->get('tmp_path')); ?>" />
	</div>
</div>
<div class="form-actions">
	<input type="button" class="btn btn-primary"
id="installbutton_directory"
		value="<?php echo
JText::_('PLG_INSTALLER_FOLDERINSTALLER_BUTTON'); ?>"
onclick="Joomla.submitbuttonfolder()" />
</div>
installer/packageinstaller/packageinstaller.php000064400000001770147357022240016107
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.packageInstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * PackageInstaller Plugin.
 *
 * @since  3.6.0
 */
class PlgInstallerPackageInstaller extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.6.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Textfield or Form of the Plugin.
	 *
	 * @return  array  Returns an array with the tab information
	 *
	 * @since   3.6.0
	 */
	public function onInstallerAddInstallationTab()
	{
		$tab            = array();
		$tab['name']    = 'package';
		$tab['label']   =
JText::_('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_PACKAGE_FILE');

		// Render the input
		ob_start();
		include JPluginHelper::getLayoutPath('installer',
'packageinstaller');
		$tab['content'] = ob_get_clean();

		return $tab;
	}
}
installer/packageinstaller/packageinstaller.xml000064400000001504147357022240016113
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin"
group="installer">
	<name>plg_installer_packageinstaller</name>
	<author>Joomla! Project</author>
	<creationDate>May 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.6.0</version>
	<description>PLG_INSTALLER_PACKAGEINSTALLER_PLUGIN_XML_DESCRIPTION</description>

	<files>
		<filename
plugin="packageinstaller">packageinstaller.php</filename>
	</files>

	<languages>
		<language
tag="en-GB">en-GB.plg_installer_packageinstaller.ini</language>
		<language
tag="en-GB">en-GB.plg_installer_packageinstaller.sys.ini</language>
	</languages>
</extension>
installer/packageinstaller/tmpl/default.php000064400000022161147357022240015173
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.packageinstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('bootstrap.tooltip');
JHtml::_('jquery.token');

JText::script('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_ERROR_UNKNOWN');
JText::script('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_ERROR_EMPTY');
JText::script('COM_INSTALLER_MSG_WARNINGS_UPLOADFILETOOBIG');

JFactory::getDocument()->addScriptDeclaration('
	Joomla.submitbuttonpackage = function()
	{
		var form = document.getElementById("adminForm");

		// do field validation 
		if (form.install_package.value == "")
		{
			alert("' .
JText::_('PLG_INSTALLER_PACKAGEINSTALLER_NO_PACKAGE', true) .
'");
		}
		else if (form.install_package.files[0].size >
form.max_upload_size.value)
		{
			alert("' .
JText::_('COM_INSTALLER_MSG_WARNINGS_UPLOADFILETOOBIG', true) .
'");
		}
		else
		{
			JoomlaInstaller.showLoading();
			form.installtype.value = "upload"
			form.submit();
		}
	};
');

// Drag and Drop installation scripts
$token = JSession::getFormToken();
$return =
JFactory::getApplication()->input->getBase64('return');

// Drag-drop installation
JFactory::getDocument()->addScriptDeclaration(
<<<JS
	jQuery(document).ready(function($) {
		if (typeof FormData === 'undefined') {
			$('#legacy-uploader').show();
			$('#uploader-wrapper').hide();
			return;
		}

		var uploading   = false;
		var dragZone    = $('#dragarea');
		var fileInput   = $('#install_package');
		var fileSizeMax = $('#max_upload_size').val();
		var button      = $('#select-file-button');
		var url         =
'index.php?option=com_installer&task=install.ajax_upload';
		var returnUrl   = $('#installer-return').val();
		var actions     = $('.upload-actions');
		var progress    = $('.upload-progress');
		var progressBar = progress.find('.bar');
		var percentage  = progress.find('.uploading-number');

		if (returnUrl) {
			url += '&return=' + returnUrl;
		}

		button.on('click', function(e) {
			fileInput.click();
		});

		fileInput.on('change', function (e) {
			if (uploading) {
				return;
			}

			Joomla.submitbuttonpackage();
		});

		dragZone.on('dragenter', function(e) {
			e.preventDefault();
			e.stopPropagation();

			dragZone.addClass('hover');

			return false;
		});

		// Notify user when file is over the drop area
		dragZone.on('dragover', function(e) {
			e.preventDefault();
			e.stopPropagation();

			dragZone.addClass('hover');

			return false;
		});

		dragZone.on('dragleave', function(e) {
			e.preventDefault();
			e.stopPropagation();
			dragZone.removeClass('hover');

			return false;
		});

		dragZone.on('drop', function(e) {
			e.preventDefault();
			e.stopPropagation();

			dragZone.removeClass('hover');

			if (uploading) {
				return;
			}

			var files = e.originalEvent.target.files ||
e.originalEvent.dataTransfer.files;

			if (!files.length) {
				return;
			}

			var file = files[0];

			var data = new FormData;

			if (file.size > fileSizeMax) {
				alert(Joomla.JText._('COM_INSTALLER_MSG_WARNINGS_UPLOADFILETOOBIG'),
true);
				return;
			}

			data.append('install_package', file);
			data.append('installtype', 'upload');

			dragZone.attr('data-state', 'uploading');
			uploading = true;

			$.ajax({
				url: url,
				data: data,
				type: 'post',
				processData: false,
				cache: false,
				contentType: false,
				xhr: function () {
					var xhr = new window.XMLHttpRequest();

					progressBar.css('width', 0);
					progressBar.attr('aria-valuenow', 0);
					percentage.text(0);

					// Upload progress
					xhr.upload.addEventListener("progress", function (evt) {
						if (evt.lengthComputable) {
							var percentComplete = evt.loaded / evt.total;
							var number = Math.round(percentComplete * 100);
							progressBar.css('width', number + '%');
							progressBar.attr('aria-valuenow', number);
							percentage.text(number);

							if (number === 100) {
								dragZone.attr('data-state', 'installing');
							}
						}
					}, false);

					return xhr;
				}
			})
			.done(function (res) {
				// Handle extension fatal error
				if (!res || (!res.success && !res.data)) {
					showError(res);
					return;
				}

				// Always redirect that can show message queue from session 
				if (res.data.redirect) {
					location.href = res.data.redirect;
				} else {
					location.href =
'index.php?option=com_installer&view=install';
				}
			}).error(function (error) {
				uploading = false;

				if (error.status === 200) {
					var res = error.responseText || error.responseJSON;
					showError(res);
				} else {
					showError(error.statusText);
				}
			});

			function showError(res) {
				dragZone.attr('data-state', 'pending');

				var message =
Joomla.JText._('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_ERROR_UNKNOWN');

				if (res == null) {
					message =
Joomla.JText._('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_ERROR_EMPTY');
				} else if (typeof res === 'string') {
					// Let's remove unnecessary HTML
					message = res.replace(/(<([^>]+)>|\s+)/g, ' ');
				} else if (res.message) {
					message = res.message;
				}

				Joomla.renderMessages({error: [message]});
			}
		});
	});
JS
);

JFactory::getDocument()->addStyleDeclaration(
<<<CSS
	#dragarea {
		background-color: #fafbfc;
		border: 1px dashed #999;
		box-sizing: border-box;
		padding: 5% 0;
		transition: all 0.2s ease 0s;
		width: 100%;
	}

	#dragarea p.lead {
		color: #999;
	}

	#upload-icon {
		font-size: 48px;
		width: auto;
		height: auto;
		margin: 0;
		line-height: 175%;
		color: #999;
		transition: all .2s;
	}

	#dragarea.hover {
		border-color: #666;
		background-color: #eee;
	}

	#dragarea.hover #upload-icon,
	#dragarea p.lead {
		color: #666;
	}

	 .upload-progress, .install-progress {
		width: 50%;
		margin: 5px auto;
	 }

	/* Default transition (.3s) is too slow, progress will not run to 100% */
	.upload-progress .progress .bar {
		-webkit-transition: width .1s;
		-moz-transition: width .1s;
		-o-transition: width .1s;
		transition: width .1s;
	}

	#dragarea[data-state=pending] .upload-progress {
		display: none;
	}

	#dragarea[data-state=pending] .install-progress {
		display: none;
	}

	#dragarea[data-state=uploading] .install-progress {
		display: none;
	}

	#dragarea[data-state=uploading] .upload-actions {
		display: none;
	}

	#dragarea[data-state=installing] .upload-progress {
		display: none;
	}

	#dragarea[data-state=installing] .upload-actions {
		display: none;
	}
CSS
);

$maxSizeBytes = JFilesystemHelper::fileUploadMaxSize(false);
$maxSize = JHtml::_('number.bytes', $maxSizeBytes);
?>
<legend><?php echo
JText::_('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_INSTALL_JOOMLA_EXTENSION');
?></legend>

<div id="uploader-wrapper">
	<div id="dragarea" data-state="pending">
		<div id="dragarea-content" class="text-center">
			<p>
				<span id="upload-icon" class="icon-upload"
aria-hidden="true"></span>
			</p>
			<div class="upload-progress">
				<div class="progress progress-striped active">
					<div class="bar bar-success"
						style="width: 0;"
						role="progressbar"
						aria-valuenow="0"
						aria-valuemin="0"
						aria-valuemax="100"
					></div>
				</div>
				<p class="lead">
					<span class="uploading-text">
						<?php echo
JText::_('PLG_INSTALLER_PACKAGEINSTALLER_UPLOADING'); ?>
					</span>
					<span class="uploading-number">0</span><span
class="uploading-symbol">%</span>
				</p>
			</div>
			<div class="install-progress">
				<div class="progress progress-striped active">
					<div class="bar" style="width:
100%;"></div>
				</div>
				<p class="lead">
					<span class="installing-text">
						<?php echo
JText::_('PLG_INSTALLER_PACKAGEINSTALLER_INSTALLING'); ?>
					</span>
				</p>
			</div>
			<div class="upload-actions">
				<p class="lead">
					<?php echo
JText::_('PLG_INSTALLER_PACKAGEINSTALLER_DRAG_FILE_HERE'); ?>
				</p>
				<p>
					<button id="select-file-button" type="button"
class="btn btn-success">
						<span class="icon-copy"
aria-hidden="true"></span>
						<?php echo
JText::_('PLG_INSTALLER_PACKAGEINSTALLER_SELECT_FILE'); ?>
					</button>
				</p>
				<p>
					<?php echo
JText::sprintf('JGLOBAL_MAXIMUM_UPLOAD_SIZE_LIMIT', $maxSize);
?>
				</p>
			</div>
		</div>
	</div>
</div>

<div id="legacy-uploader" style="display: none;">
	<div class="control-group">
		<label for="install_package"
class="control-label"><?php echo
JText::_('PLG_INSTALLER_PACKAGEINSTALLER_EXTENSION_PACKAGE_FILE');
?></label>
		<div class="controls">
			<input class="input_box" id="install_package"
name="install_package" type="file" size="57"
/>
			<input id="max_upload_size"
name="max_upload_size" type="hidden"
value="<?php echo $maxSizeBytes; ?>" /><br>
			<?php echo
JText::sprintf('JGLOBAL_MAXIMUM_UPLOAD_SIZE_LIMIT', $maxSize);
?>
		</div>
	</div>
	<div class="form-actions">
		<button class="btn btn-primary" type="button"
id="installbutton_package"
onclick="Joomla.submitbuttonpackage()">
			<?php echo
JText::_('PLG_INSTALLER_PACKAGEINSTALLER_UPLOAD_AND_INSTALL');
?>
		</button>
	</div>

	<input id="installer-return" name="return"
type="hidden" value="<?php echo $return; ?>"
/>
	<input id="installer-token" name="return"
type="hidden" value="<?php echo $token; ?>" />
</div>
installer/urlinstaller/tmpl/default.php000064400000002141147357022240014376
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.urlinstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JHtml::_('bootstrap.tooltip');

JFactory::getDocument()->addScriptDeclaration('
	Joomla.submitbuttonurl = function()
	{
		var form = document.getElementById("adminForm");

		JoomlaInstaller.showLoading();
		form.installtype.value = "url"
		form.submit();
	};
');
?>
<legend><?php echo
JText::_('PLG_INSTALLER_URLINSTALLER_TEXT'); ?></legend>
<div class="control-group">
	<label for="install_url"
class="control-label"><?php echo
JText::_('PLG_INSTALLER_URLINSTALLER_TEXT'); ?></label>
	<div class="controls">
		<input type="text" id="install_url"
name="install_url" class="span5 input_box"
size="70" placeholder="https://"/>
	</div>
</div>
<div class="form-actions">
	<input type="button" class="btn btn-primary"
id="installbutton_url"
		value="<?php echo
JText::_('PLG_INSTALLER_URLINSTALLER_BUTTON'); ?>"
onclick="Joomla.submitbuttonurl()" />
</div>
installer/urlinstaller/urlinstaller.php000064400000001726147357022240014526
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Installer.urlinstaller
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

/**
 * UrlFolderInstaller Plugin.
 *
 * @since  3.6.0
 */
class PlgInstallerUrlInstaller extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.6.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Textfield or Form of the Plugin.
	 *
	 * @return  array  Returns an array with the tab information
	 *
	 * @since   3.6.0
	 */
	public function onInstallerAddInstallationTab()
	{
		$tab            = array();
		$tab['name']    = 'url';
		$tab['label']   =
JText::_('PLG_INSTALLER_URLINSTALLER_TEXT');

		// Render the input
		ob_start();
		include JPluginHelper::getLayoutPath('installer',
'urlinstaller');
		$tab['content'] = ob_get_clean();

		return $tab;
	}
}
installer/urlinstaller/urlinstaller.xml000064400000001454147357022240014535
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin"
group="installer">
	<name>PLG_INSTALLER_URLINSTALLER</name>
	<author>Joomla! Project</author>
	<creationDate>May 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.6.0</version>
	<description>PLG_INSTALLER_URLINSTALLER_PLUGIN_XML_DESCRIPTION</description>

	<files>
		<filename
plugin="urlinstaller">urlinstaller.php</filename>
	</files>

	<languages>
		<language
tag="en-GB">en-GB.plg_installer_urlinstaller.ini</language>
		<language
tag="en-GB">en-GB.plg_installer_urlinstaller.sys.ini</language>
	</languages>
</extension>
privacy/actionlogs/actionlogs.php000064400000003334147357022240013247
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.actionlogs
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR .
'/components/com_actionlogs/helpers/actionlogs.php');
JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR .
'/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla actionlogs data
 *
 * @since  3.9.0
 */
class PlgPrivacyActionlogs extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core actionlog data
	 *
	 * @param   PrivacyTableRequest  $request  The request record being
processed
	 * @param   JUser                $user     The user account associated
with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser
$user = null)
	{
		if (!$user)
		{
			return array();
		}

		$domain = $this->createDomain('user_action_logs',
'joomla_user_action_logs_data');

		$query = $this->db->getQuery(true)
			->select('a.*, u.name')
			->from('#__action_logs AS a')
			->innerJoin('#__users AS u ON a.user_id = u.id')
			->where($this->db->quoteName('a.user_id') . ' =
' . (int) $user->id);

		$this->db->setQuery($query);

		$data = $this->db->loadObjectList();

		if (!count($data))
		{
			return array();
		}

		$data    = ActionlogsHelper::getCsvData($data);
		$isFirst = true;

		foreach ($data as $item)
		{
			if ($isFirst)
			{
				$isFirst = false;

				continue;
			}

			$domain->addItem($this->createItemFromArray($item));
		}

		return array($domain);
	}
}
privacy/actionlogs/actionlogs.xml000064400000001437147357022240013262
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="privacy" method="upgrade">
	<name>plg_privacy_actionlogs</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_ACTIONLOGS_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="actionlogs">actionlogs.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_privacy_actionlogs.ini</language>
		<language
tag="en-GB">en-GB.plg_privacy_actionlogs.sys.ini</language>
	</languages>
</extension>
privacy/consents/consents.php000064400000002761147357022240012436
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.consents
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR .
'/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla user consent data
 *
 * @since  3.9.0
 */
class PlgPrivacyConsents extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core user consent data
	 *
	 * This event will collect data for the core `#__privacy_consents` table
	 *
	 * @param   PrivacyTableRequest  $request  The request record being
processed
	 * @param   JUser                $user     The user account associated
with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser
$user = null)
	{
		if (!$user)
		{
			return array();
		}

		$domain    = $this->createDomain('consents',
'joomla_consent_data');

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__privacy_consents'))
			->where($this->db->quoteName('user_id') . ' =
' . (int) $user->id)
			->order($this->db->quoteName('created') . '
ASC');

		$items = $this->db->setQuery($query)->loadAssocList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray($item));
		}

		return array($domain);
	}
}
privacy/consents/consents.xml000064400000001423147357022240012441
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="privacy" method="upgrade">
	<name>plg_privacy_consents</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_CONSENTS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="consents">consents.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_privacy_consents.ini</language>
		<language
tag="en-GB">en-GB.plg_privacy_consents.sys.ini</language>
	</languages>
</extension>
privacy/contact/contact.php000064400000003457147357022240012037
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.contact
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR .
'/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla user contact data
 *
 * @since  3.9.0
 */
class PlgPrivacyContact extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core user contact data
	 *
	 * This event will collect data for the contact core tables:
	 *
	 * - Contact custom fields
	 *
	 * @param   PrivacyTableRequest  $request  The request record being
processed
	 * @param   JUser                $user     The user account associated
with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser
$user = null)
	{
		if (!$user && !$request->email)
		{
			return array();
		}

		$domains   = array();
		$domain    = $this->createDomain('user_contact',
'joomla_user_contact_data');
		$domains[] = $domain;

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__contact_details'))
			->order($this->db->quoteName('ordering') . '
ASC');

		if ($user)
		{
			$query->where($this->db->quoteName('user_id') .
' = ' . (int) $user->id);
		}
		else
		{
			$query->where($this->db->quoteName('email_to') .
' = ' . $this->db->quote($request->email));
		}

		$items = $this->db->setQuery($query)->loadObjectList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray((array) $item));
		}

		$domains[] =
$this->createCustomFieldsDomain('com_contact.contact',
$items);

		return $domains;
	}
}
privacy/contact/contact.xml000064400000001415147357022240012040
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="privacy" method="upgrade">
	<name>plg_privacy_contact</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_CONTACT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contact">contact.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_privacy_contact.ini</language>
		<language
tag="en-GB">en-GB.plg_privacy_contact.sys.ini</language>
	</languages>
</extension>
privacy/content/content.php000064400000003210147357022240012060
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.content
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR .
'/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla user content data
 *
 * @since  3.9.0
 */
class PlgPrivacyContent extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core user content data
	 *
	 * This event will collect data for the content core table
	 *
	 * - Content custom fields
	 *
	 * @param   PrivacyTableRequest  $request  The request record being
processed
	 * @param   JUser                $user     The user account associated
with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser
$user = null)
	{
		if (!$user)
		{
			return array();
		}

		$domains   = array();
		$domain    = $this->createDomain('user_content',
'joomla_user_content_data');
		$domains[] = $domain;

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__content'))
			->where($this->db->quoteName('created_by') . ' =
' . (int) $user->id)
			->order($this->db->quoteName('ordering') . '
ASC');

		$items = $this->db->setQuery($query)->loadObjectList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray((array) $item));
		}

		$domains[] =
$this->createCustomFieldsDomain('com_content.article',
$items);

		return $domains;
	}
}
privacy/content/content.xml000064400000001415147357022240012076
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="privacy" method="upgrade">
	<name>plg_privacy_content</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_CONTENT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="content">content.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_privacy_content.ini</language>
		<language
tag="en-GB">en-GB.plg_privacy_content.sys.ini</language>
	</languages>
</extension>
privacy/message/message.php000064400000003045147357022240012012
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.message
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR .
'/components/com_privacy/helpers/plugin.php');

/**
 * Privacy plugin managing Joomla user messages
 *
 * @since  3.9.0
 */
class PlgPrivacyMessage extends PrivacyPlugin
{
	/**
	 * Processes an export request for Joomla core user message
	 *
	 * This event will collect data for the message table
	 *
	 * @param   PrivacyTableRequest  $request  The request record being
processed
	 * @param   JUser                $user     The user account associated
with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser
$user = null)
	{
		if (!$user)
		{
			return array();
		}

		$domain = $this->createDomain('user_messages',
'joomla_user_messages_data');

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__messages'))
			->where($this->db->quoteName('user_id_from') . '
= ' . (int) $user->id)
			->orWhere($this->db->quoteName('user_id_to') . '
= ' . (int) $user->id)
			->order($this->db->quoteName('date_time') . '
ASC');

		$items = $this->db->setQuery($query)->loadAssocList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray($item));
		}

		return array($domain);
	}
}
privacy/message/message.xml000064400000001415147357022240012022
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="privacy" method="upgrade">
	<name>plg_privacy_message</name>
	<author>Joomla! Project</author>
	<creationDate>July 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_MESSAGE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="message">message.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_privacy_message.ini</language>
		<language
tag="en-GB">en-GB.plg_privacy_message.sys.ini</language>
	</languages>
</extension>
privacy/user/user.php000064400000013507147357022240010702 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Privacy.user
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\User\UserHelper;
use Joomla\Utilities\ArrayHelper;

JLoader::register('PrivacyPlugin', JPATH_ADMINISTRATOR .
'/components/com_privacy/helpers/plugin.php');
JLoader::register('PrivacyRemovalStatus', JPATH_ADMINISTRATOR .
'/components/com_privacy/helpers/removal/status.php');

/**
 * Privacy plugin managing Joomla user data
 *
 * @since  3.9.0
 */
class PlgPrivacyUser extends PrivacyPlugin
{
	/**
	 * Performs validation to determine if the data associated with a remove
information request can be processed
	 *
	 * This event will not allow a super user account to be removed
	 *
	 * @param   PrivacyTableRequest  $request  The request record being
processed
	 * @param   JUser                $user     The user account associated
with this request if available
	 *
	 * @return  PrivacyRemovalStatus
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCanRemoveData(PrivacyTableRequest $request, JUser
$user = null)
	{
		$status = new PrivacyRemovalStatus;

		if (!$user)
		{
			return $status;
		}

		if ($user->authorise('core.admin'))
		{
			$status->canRemove = false;
			$status->reason    =
JText::_('PLG_PRIVACY_USER_ERROR_CANNOT_REMOVE_SUPER_USER');
		}

		return $status;
	}

	/**
	 * Processes an export request for Joomla core user data
	 *
	 * This event will collect data for the following core tables:
	 *
	 * - #__users (excluding the password, otpKey, and otep columns)
	 * - #__user_notes
	 * - #__user_profiles
	 * - User custom fields
	 *
	 * @param   PrivacyTableRequest  $request  The request record being
processed
	 * @param   JUser                $user     The user account associated
with this request if available
	 *
	 * @return  PrivacyExportDomain[]
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyExportRequest(PrivacyTableRequest $request, JUser
$user = null)
	{
		if (!$user)
		{
			return array();
		}

		/** @var JTableUser $userTable */
		$userTable = JUser::getTable();
		$userTable->load($user->id);

		$domains = array();
		$domains[] = $this->createUserDomain($userTable);
		$domains[] = $this->createNotesDomain($userTable);
		$domains[] = $this->createProfileDomain($userTable);
		$domains[] =
$this->createCustomFieldsDomain('com_users.user',
array($userTable));

		return $domains;
	}

	/**
	 * Removes the data associated with a remove information request
	 *
	 * This event will pseudoanonymise the user account
	 *
	 * @param   PrivacyTableRequest  $request  The request record being
processed
	 * @param   JUser                $user     The user account associated
with this request if available
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyRemoveData(PrivacyTableRequest $request, JUser
$user = null)
	{
		// This plugin only processes data for registered user accounts
		if (!$user)
		{
			return;
		}

		$pseudoanonymisedData = array(
			'name'      => 'User ID ' . $user->id,
			'username'  => bin2hex(random_bytes(12)),
			'email'     => 'UserID' . $user->id .
'removed@email.invalid',
			'block'     => true,
		);

		$user->bind($pseudoanonymisedData);

		$user->save();

		// Destroy all sessions for the user account
		UserHelper::destroyUserSessions($user->id);
	}

	/**
	 * Create the domain for the user notes data
	 *
	 * @param   JTableUser  $user  The JTableUser object to process
	 *
	 * @return  PrivacyExportDomain
	 *
	 * @since   3.9.0
	 */
	private function createNotesDomain(JTableUser $user)
	{
		$domain = $this->createDomain('user_notes',
'joomla_user_notes_data');

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__user_notes'))
			->where($this->db->quoteName('user_id') . ' =
' . $this->db->quote($user->id));

		$items = $this->db->setQuery($query)->loadAssocList();

		// Remove user ID columns
		foreach (array('user_id', 'created_user_id',
'modified_user_id') as $column)
		{
			$items = ArrayHelper::dropColumn($items, $column);
		}

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray($item,
$item['id']));
		}

		return $domain;
	}

	/**
	 * Create the domain for the user profile data
	 *
	 * @param   JTableUser  $user  The JTableUser object to process
	 *
	 * @return  PrivacyExportDomain
	 *
	 * @since   3.9.0
	 */
	private function createProfileDomain(JTableUser $user)
	{
		$domain = $this->createDomain('user_profile',
'joomla_user_profile_data');

		$query = $this->db->getQuery(true)
			->select('*')
			->from($this->db->quoteName('#__user_profiles'))
			->where($this->db->quoteName('user_id') . ' =
' . $this->db->quote($user->id))
			->order($this->db->quoteName('ordering') . '
ASC');

		$items = $this->db->setQuery($query)->loadAssocList();

		foreach ($items as $item)
		{
			$domain->addItem($this->createItemFromArray($item));
		}

		return $domain;
	}

	/**
	 * Create the domain for the user record
	 *
	 * @param   JTableUser  $user  The JTableUser object to process
	 *
	 * @return  PrivacyExportDomain
	 *
	 * @since   3.9.0
	 */
	private function createUserDomain(JTableUser $user)
	{
		$domain = $this->createDomain('users',
'joomla_users_data');
		$domain->addItem($this->createItemForUserTable($user));

		return $domain;
	}

	/**
	 * Create an item object for a JTableUser object
	 *
	 * @param   JTableUser  $user  The JTableUser object to convert
	 *
	 * @return  PrivacyExportItem
	 *
	 * @since   3.9.0
	 */
	private function createItemForUserTable(JTableUser $user)
	{
		$data    = array();
		$exclude = array('password', 'otpKey',
'otep');

		foreach (array_keys($user->getFields()) as $fieldName)
		{
			if (!in_array($fieldName, $exclude))
			{
				$data[$fieldName] = $user->$fieldName;
			}
		}

		return $this->createItemFromArray($data, $user->id);
	}
}
privacy/user/user.xml000064400000001372147357022240010710 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="privacy" method="upgrade">
	<name>plg_privacy_user</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_PRIVACY_USER_XML_DESCRIPTION</description>
	<files>
		<filename plugin="user">user.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_privacy_user.ini</language>
		<language
tag="en-GB">en-GB.plg_privacy_user.sys.ini</language>
	</languages>
</extension>
quickicon/eos310/eos310.php000064400000025036147357022240011302
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.eos310
 *
 * @copyright   (C) 2021 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;

/**
 * Joomla! end of support notification plugin
 *
 * @since  3.10.0
 */
class PlgQuickiconEos310 extends CMSPlugin
{
	/**
	 * The EOS date for 3.10
	 *
	 * @var    string
	 * @since  3.10.0
	 */
	const EOS_DATE = '2023-08-17';

	/**
	 * Application object
	 *
	 * @var    CMSApplication
	 * @since  3.10.0
	 */
	protected $app;

	/**
	 * Database object
	 *
	 * @var    DatabaseDriver
	 * @since  3.10.0
	 */
	protected $db;

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.10.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Holding the current valid message to be shown
	 *
	 * @var    boolean
	 * @since  3.10.0
	 */
	private $currentMessage = false;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of
configuration settings.
	 *
	 * @since   3.10.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		$diff           =
Factory::getDate()->diff(Factory::getDate(static::EOS_DATE));
		$monthsUntilEOS = floor($diff->days / 30.417);

		$this->currentMessage = $this->getMessageInfo($monthsUntilEOS,
$diff->invert);
	}

	/**
	 * Check and show the the alert and quickicon message
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  array|void  A list of icon definition associative arrays,
consisting of the
	 *			keys link, image, text and access, or void.
	 *
	 * @since   3.10.0
	 */
	public function onGetIcons($context)
	{
		if (!$this->shouldDisplayMessage())
		{
			return;
		}

		// No messages yet
		if (!$this->currentMessage)
		{
			return;
		}

		// Show this only when not snoozed
		if ($this->params->get('last_snoozed_id', 0) <
$this->currentMessage['id'])
		{
			// Load the snooze scripts.
			HTMLHelper::_('jquery.framework');
			HTMLHelper::_('script',
'plg_quickicon_eos310/snooze.js', array('version' =>
'auto', 'relative' => true));

			// Build the  message to be displayed in the cpanel
			$messageText = Text::sprintf(
				$this->currentMessage['messageText'],
				HTMLHelper::_('date', static::EOS_DATE,
Text::_('DATE_FORMAT_LC3')),
				$this->currentMessage['messageLink']
			);

			if ($this->currentMessage['snoozable'])
			{
				$messageText .=
					'<p><button class="btn btn-warning
eosnotify-snooze-btn" type="button">' .
					Text::_('PLG_QUICKICON_EOS310_SNOOZE_BUTTON') .
					'</button></p>';
			}

			$this->app->enqueueMessage(
				$messageText,
				$this->currentMessage['messageType']
			);
		}

		// The message as quickicon
		$messageTextQuickIcon = Text::sprintf(
			$this->currentMessage['quickiconText'],
			HTMLHelper::_(
				'date',
				static::EOS_DATE,
				Text::_('DATE_FORMAT_LC3')
			)
		);

		// The message as quickicon
		return array(array(
			'link'   =>
$this->currentMessage['messageLink'],
			'target' => '_blank',
			'rel'    => 'noopener noreferrer',
			'image'  => $this->currentMessage['image'],
			'text'   => $messageTextQuickIcon,
			'id'	 => 'plg_quickicon_eos310',
			'group'  =>
$this->currentMessage['groupText'],
		));
	}

	/**
	 * User hit the snooze button
	 *
	 * @return  void
	 *
	 * @since   3.10.0
	 *
	 * @throws  JAccessExceptionNotallowed  If user is not allowed.
	 */
	public function onAjaxSnoozeEOS()
	{
		// No messages yet so nothing to snooze
		if (!$this->currentMessage)
		{
			return;
		}

		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new
JAccessExceptionNotallowed(Text::_('JGLOBAL_AUTH_ACCESS_DENIED'),
403);
		}

		// Make sure only snoozable messages can be snoozed
		if ($this->currentMessage['snoozable'])
		{
			$this->params->set('last_snoozed_id',
$this->currentMessage['id']);

			$this->saveParams();
		}
	}

	/**
	 * Return the texts to be displayed based on the time until we reach EOS
	 *
	 * @param   integer  $monthsUntilEOS  The months until we reach EOS
	 * @param   integer  $inverted        Have we surpassed the EOS date
	 *
	 * @return  array|bool  An array with the message to be displayed or false
	 *
	 * @since   3.10.0
	 */
	private function getMessageInfo($monthsUntilEOS, $inverted)
	{
		// The EOS date has passed - Support has ended
		if ($inverted === 1)
		{
			return array(
				'id'            => 5,
				'messageText'   =>
'PLG_QUICKICON_EOS310_MESSAGE_ERROR_SUPPORT_ENDED',
				'quickiconText' =>
'PLG_QUICKICON_EOS310_MESSAGE_ERROR_SUPPORT_ENDED_SHORT',
				'messageType'   => 'error',
				'image'         => 'minus-circle',
				'messageLink'   =>
'https://docs.joomla.org/Special:MyLanguage/Planning_for_Mini-Migration_-_Joomla_3.10.x_to_4.x',
				'groupText'     =>
'PLG_QUICKICON_EOS310_GROUPNAME_EOS',
				'snoozable'     => false,
			);
		}

		// The security support is ending in 6 months
		if ($monthsUntilEOS < 6)
		{
			return array(
				'id'            => 4,
				'messageText'   =>
'PLG_QUICKICON_EOS310_MESSAGE_WARNING_SUPPORT_ENDING',
				'quickiconText' =>
'PLG_QUICKICON_EOS310_MESSAGE_WARNING_SUPPORT_ENDING_SHORT',
				'messageType'   => 'warning',
				'image'         => 'warning-circle',
				'messageLink'   =>
'https://docs.joomla.org/Special:MyLanguage/Planning_for_Mini-Migration_-_Joomla_3.10.x_to_4.x',
				'groupText'     =>
'PLG_QUICKICON_EOS310_GROUPNAME_WARNING',
				'snoozable'     => true,
			);
		}

		// We are in security only mode now, 12 month to go from now on
		if ($monthsUntilEOS < 12)
		{
			return array(
				'id'            => 3,
				'messageText'   =>
'PLG_QUICKICON_EOS310_MESSAGE_WARNING_SECURITY_ONLY',
				'quickiconText' =>
'PLG_QUICKICON_EOS310_MESSAGE_WARNING_SECURITY_ONLY_SHORT',
				'messageType'   => 'warning',
				'image'         => 'warning-circle',
				'messageLink'   =>
'https://docs.joomla.org/Special:MyLanguage/Planning_for_Mini-Migration_-_Joomla_3.10.x_to_4.x',
				'groupText'     =>
'PLG_QUICKICON_EOS310_GROUPNAME_WARNING',
				'snoozable'     => true,
			);
		}

		// We still have 16 month to go, lets remind our users about the pre
upgrade checker
		if ($monthsUntilEOS < 16)
		{
			return array(
				'id'            => 2,
				'messageText'   =>
'PLG_QUICKICON_EOS310_MESSAGE_INFO_02',
				'quickiconText' =>
'PLG_QUICKICON_EOS310_MESSAGE_INFO_02_SHORT',
				'messageType'   => 'info',
				'image'         => 'info-circle',
				'messageLink'   =>
'https://docs.joomla.org/Special:MyLanguage/Pre-Update_Check',
				'groupText'     =>
'PLG_QUICKICON_EOS310_GROUPNAME_INFO',
				'snoozable'     => true,
			);
		}

		// Lets start our messages 2 month after the initial release, still 22
month to go
		if ($monthsUntilEOS < 22)
		{
			return array(
				'id'            => 1,
				'messageText'   =>
'PLG_QUICKICON_EOS310_MESSAGE_INFO_01',
				'quickiconText' =>
'PLG_QUICKICON_EOS310_MESSAGE_INFO_01_SHORT',
				'messageType'   => 'info',
				'image'         => 'info-circle',
				'messageLink'   =>
'https://www.joomla.org/4/#features',
				'groupText'     =>
'PLG_QUICKICON_EOS310_GROUPNAME_INFO',
				'snoozable'     => true,
			);
		}

		return false;
	}

	/**
	 * Determines if the message and quickicon should be displayed
	 *
	 * @return  boolean
	 *
	 * @since   3.10.0
	 */
	private function shouldDisplayMessage()
	{
		// Only on admin app
		if (!$this->app->isClient('administrator'))
		{
			return false;
		}

		// Only if authenticated
		if (Factory::getUser()->guest)
		{
			return false;
		}

		// Only on HTML documents
		if ($this->app->getDocument()->getType() !== 'html')
		{
			return false;
		}

		// Only on full page requests
		if ($this->app->input->getCmd('tmpl',
'index') === 'component')
		{
			return false;
		}

		// Only to com_cpanel
		if ($this->app->input->get('option') !==
'com_cpanel')
		{
			return false;
		}

		// Don't show anything in 4.0
		if (version_compare(JVERSION, '4.0', '>='))
		{
			return false;
		}

		return true;
	}

	/**
	 * Check valid AJAX request
	 *
	 * @return  boolean
	 *
	 * @since   3.10.0
	 */
	private function isAjaxRequest()
	{
		return
strtolower($this->app->input->server->get('HTTP_X_REQUESTED_WITH',
'')) === 'xmlhttprequest';
	}

	/**
	 * Check if current user is allowed to send the data
	 *
	 * @return  boolean
	 *
	 * @since   3.10.0
	 */
	private function isAllowedUser()
	{
		return Factory::getUser()->authorise('core.login.admin');
	}

	/**
	 * Save the plugin parameters
	 *
	 * @return  boolean
	 *
	 * @since   3.10.0
	 */
	private function saveParams()
	{
		$query = $this->db->getQuery(true)
			->update($this->db->quoteName('#__extensions'))
			->set($this->db->quoteName('params') . ' =
' .
$this->db->quote($this->params->toString('JSON')))
			->where($this->db->quoteName('type') . ' =
' . $this->db->quote('plugin'))
			->where($this->db->quoteName('folder') . ' =
' . $this->db->quote('quickicon'))
			->where($this->db->quoteName('element') . ' =
' . $this->db->quote('eos310'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race
condition
			$this->db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue
execution
			return false;
		}

		try
		{
			// Update the plugin parameters
			$result = $this->db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$this->db->unlockTables();

			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$this->db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		return $result;
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.10.0
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
	{
		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'	=> $client_id ? JPATH_ADMINISTRATOR .
'/cache' : $this->app->get('cache_path',
JPATH_SITE . '/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
quickicon/eos310/eos310.xml000064400000001670147357022240011311
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.10" type="plugin"
group="quickicon" method="upgrade">
	<name>plg_quickicon_eos310</name>
	<author>Joomla! Project</author>
	<creationDate>June 2021</creationDate>
	<copyright>(C) 2021 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.10.0</version>
	<description>PLG_QUICKICON_EOS310_XML_DESCRIPTION</description>
	<files>
		<filename plugin="eos310">eos310.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_quickicon_eos310.ini</language>
		<language
tag="en-GB">en-GB.plg_quickicon_eos310.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="last_snoozed_id"
					type="hidden"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
quickicon/extensionupdate/extensionupdate.php000064400000005161147357022240015711
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.Extensionupdate
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! update notification plugin
 *
 * @since  2.5
 */
class PlgQuickiconExtensionupdate extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Returns an icon definition for an icon which looks for extensions
updates
	 * via AJAX and displays a notification when such updates are found.
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  array  A list of icon definition associative arrays,
consisting of the
	 *                 keys link, image, text and access.
	 *
	 * @since   2.5
	 */
	public function onGetIcons($context)
	{
		if ($context !== $this->params->get('context',
'mod_quickicon') ||
!JFactory::getUser()->authorise('core.manage',
'com_installer'))
		{
			return;
		}

		JHtml::_('jquery.framework');

		$token    = JSession::getFormToken() . '=' . 1;
		$url      = JUri::base() .
'index.php?option=com_installer&view=update&task=update.find&'
. $token;
		$ajax_url = JUri::base() .
'index.php?option=com_installer&view=update&task=update.ajax&'
. $token;
		$script   = array();
		$script[] = 'var plg_quickicon_extensionupdate_url = \'' .
$url . '\';';
		$script[] = 'var plg_quickicon_extensionupdate_ajax_url =
\'' . $ajax_url . '\';';
		$script[] = 'var plg_quickicon_extensionupdate_text = {'
			. '"UPTODATE" : "' .
JText::_('PLG_QUICKICON_EXTENSIONUPDATE_UPTODATE', true) .
'",'
			. '"UPDATEFOUND": "' .
JText::_('PLG_QUICKICON_EXTENSIONUPDATE_UPDATEFOUND', true) .
'",'
			. '"UPDATEFOUND_MESSAGE": "' .
JText::_('PLG_QUICKICON_EXTENSIONUPDATE_UPDATEFOUND_MESSAGE',
true) . '",'
			. '"UPDATEFOUND_BUTTON": "' .
JText::_('PLG_QUICKICON_EXTENSIONUPDATE_UPDATEFOUND_BUTTON',
true) . '",'
			. '"ERROR": "' .
JText::_('PLG_QUICKICON_EXTENSIONUPDATE_ERROR', true) .
'",'
			. '};';
		JFactory::getDocument()->addScriptDeclaration(implode("\n",
$script));
		JHtml::_('script',
'plg_quickicon_extensionupdate/extensionupdatecheck.js',
array('version' => 'auto', 'relative'
=> true));

		return array(
			array(
				'link'  =>
'index.php?option=com_installer&view=update&task=update.find&'
. $token,
				'image' => 'asterisk',
				'icon'  => 'header/icon-48-extension.png',
				'text'  =>
JText::_('PLG_QUICKICON_EXTENSIONUPDATE_CHECKING'),
				'id'    => 'plg_quickicon_extensionupdate',
				'group' => 'MOD_QUICKICON_MAINTENANCE'
			)
		);
	}
}
quickicon/extensionupdate/extensionupdate.xml000064400000002165147357022240015723
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="quickicon" method="upgrade">
	<name>plg_quickicon_extensionupdate</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_QUICKICON_EXTENSIONUPDATE_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="extensionupdate">extensionupdate.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_quickicon_extensionupdate.ini</language>
		<language
tag="en-GB">en-GB.plg_quickicon_extensionupdate.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field 
					name="context"
					type="text"
					label="PLG_QUICKICON_EXTENSIONUPDATE_GROUP_LABEL"
					description="PLG_QUICKICON_EXTENSIONUPDATE_GROUP_DESC"
					default="mod_quickicon"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
quickicon/joomlaupdate/joomlaupdate.php000064400000006116147357022240014424
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.Joomlaupdate
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! update notification plugin
 *
 * @since  2.5
 */
class PlgQuickiconJoomlaupdate extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * This method is called when the Quick Icons module is constructing its
set
	 * of icons. You can return an array which defines a single icon and it
will
	 * be rendered right after the stock Quick Icons.
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  array  A list of icon definition associative arrays,
consisting of the
	 *                 keys link, image, text and access.
	 *
	 * @since   2.5
	 */
	public function onGetIcons($context)
	{
		if ($context !== $this->params->get('context',
'mod_quickicon') ||
!JFactory::getUser()->authorise('core.manage',
'com_joomlaupdate'))
		{
			return;
		}

		JHtml::_('jquery.framework');

		$currentTemplate = JFactory::getApplication()->getTemplate();

		$url      = JUri::base() . 'index.php?option=com_joomlaupdate';
		$ajaxUrl  = JUri::base() .
'index.php?option=com_joomlaupdate&task=update.ajax&' .
JSession::getFormToken() . '=1';
		$script   = array();
		$script[] = 'var plg_quickicon_joomlaupdate_url = \'' .
$url . '\';';
		$script[] = 'var plg_quickicon_joomlaupdate_ajax_url = \''
. $ajaxUrl . '\';';
		$script[] = 'var plg_quickicon_jupdatecheck_jversion = \''
. JVERSION . '\'';
		$script[] = 'var plg_quickicon_joomlaupdate_text = {'
			. '"UPTODATE" : "' .
JText::_('PLG_QUICKICON_JOOMLAUPDATE_UPTODATE', true) .
'",'
			. '"UPDATEFOUND": "' .
JText::_('PLG_QUICKICON_JOOMLAUPDATE_UPDATEFOUND', true) .
'",'
			. '"UPDATEFOUND_MESSAGE": "' .
JText::_('PLG_QUICKICON_JOOMLAUPDATE_UPDATEFOUND_MESSAGE', true)
. '",'
			. '"UPDATEFOUND_BUTTON": "' .
JText::_('PLG_QUICKICON_JOOMLAUPDATE_UPDATEFOUND_BUTTON', true) .
'",'
			. '"ERROR": "' .
JText::_('PLG_QUICKICON_JOOMLAUPDATE_ERROR', true) .
'",'
			. '};';
		$script[] = 'var plg_quickicon_joomlaupdate_img = {'
			. '"UPTODATE" : "' . JUri::base(true) .
'/templates/' . $currentTemplate .
'/images/header/icon-48-jupdate-uptodate.png",'
			. '"UPDATEFOUND": "' . JUri::base(true) .
'/templates/' . $currentTemplate .
'/images/header/icon-48-jupdate-updatefound.png",'
			. '"ERROR": "' . JUri::base(true) .
'/templates/' . $currentTemplate .
'/images/header/icon-48-deny.png",'
			. '};';
		JFactory::getDocument()->addScriptDeclaration(implode("\n",
$script));
		JHtml::_('script',
'plg_quickicon_joomlaupdate/jupdatecheck.js',
array('version' => 'auto', 'relative'
=> true));

		return array(
			array(
				'link' => 'index.php?option=com_joomlaupdate',
				'image' => 'joomla',
				'icon' => 'header/icon-48-download.png',
				'text' =>
JText::_('PLG_QUICKICON_JOOMLAUPDATE_CHECKING'),
				'id' => 'plg_quickicon_joomlaupdate',
				'group' => 'MOD_QUICKICON_MAINTENANCE'
			)
		);
	}
}
quickicon/joomlaupdate/joomlaupdate.xml000064400000002134147357022240014431
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="quickicon" method="upgrade">
	<name>plg_quickicon_joomlaupdate</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_QUICKICON_JOOMLAUPDATE_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="joomlaupdate">joomlaupdate.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_quickicon_joomlaupdate.ini</language>
		<language
tag="en-GB">en-GB.plg_quickicon_joomlaupdate.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="context"
					type="text"
					label="PLG_QUICKICON_JOOMLAUPDATE_GROUP_LABEL"
					description="PLG_QUICKICON_JOOMLAUPDATE_GROUP_DESC"
					default="mod_quickicon"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
quickicon/phpversioncheck/phpversioncheck.php000064400000013707147357022240015646
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.phpversioncheck
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Plugin to check the PHP version and display a warning about its support
status
 *
 * @since  3.7.0
 */
class PlgQuickiconPhpVersionCheck extends JPlugin
{
	/**
	 * Constant representing the active PHP version being fully supported
	 *
	 * @var    integer
	 * @since  3.7.0
	 */
	const PHP_SUPPORTED = 0;

	/**
	 * Constant representing the active PHP version receiving security support
only
	 *
	 * @var    integer
	 * @since  3.7.0
	 */
	const PHP_SECURITY_ONLY = 1;

	/**
	 * Constant representing the active PHP version being unsupported
	 *
	 * @var    integer
	 * @since  3.7.0
	 */
	const PHP_UNSUPPORTED = 2;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.7.0
	 */
	protected $app;

	/**
	 * Load plugin language files automatically
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Check the PHP version after the admin component has been dispatched.
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  void
	 *
	 * @since   3.7.0
	 */
	public function onGetIcons($context)
	{
		if (!$this->shouldDisplayMessage())
		{
			return;
		}

		$supportStatus = $this->getPhpSupport();

		if ($supportStatus['status'] !== self::PHP_SUPPORTED)
		{
			// Enqueue the notification message; set a warning if receiving security
support or "error" if unsupported
			switch ($supportStatus['status'])
			{
				case self::PHP_SECURITY_ONLY:
					$this->app->enqueueMessage($supportStatus['message'],
'warning');

					break;

				case self::PHP_UNSUPPORTED:
					$this->app->enqueueMessage($supportStatus['message'],
'error');

					break;
			}
		}
	}

	/**
	 * Gets PHP support status.
	 *
	 * @return  array  Array of PHP support data
	 *
	 * @since   3.7.0
	 * @note    The dates used in this method should correspond to the dates
given on PHP.net
	 * @link    https://www.php.net/supported-versions.php
	 * @link    https://www.php.net/eol.php
	 */
	private function getPhpSupport()
	{
		$phpSupportData = array(
			'5.3' => array(
				'security' => '2013-07-11',
				'eos'      => '2014-08-14',
			),
			'5.4' => array(
				'security' => '2014-09-14',
				'eos'      => '2015-09-14',
			),
			'5.5' => array(
				'security' => '2015-07-10',
				'eos'      => '2016-07-21',
			),
			'5.6' => array(
				'security' => '2017-01-19',
				'eos'      => '2018-12-31',
			),
			'7.0' => array(
				'security' => '2017-12-03',
				'eos'      => '2018-12-03',
			),
			'7.1' => array(
				'security' => '2018-12-01',
				'eos'      => '2019-12-01',
			),
			'7.2' => array(
				'security' => '2019-11-30',
				'eos'      => '2020-11-30',
			),
			'7.3' => array(
				'security' => '2020-12-06',
				'eos'      => '2021-12-06',
			),
			'7.4' => array(
				'security' => '2021-11-28',
				'eos'      => '2022-11-28',
			),
			'8.0' => array(
				'security' => '2022-11-26',
				'eos'      => '2023-11-26',
			),
			'8.1' => array(
				'security' => '2023-11-25',
				'eos'      => '2024-11-25',
			),
		);

		// Fill our return array with default values
		$supportStatus = array(
			'status'  => self::PHP_SUPPORTED,
			'message' => null,
		);

		// Check the PHP version's support status using the minor version
		$activePhpVersion = PHP_MAJOR_VERSION . '.' .
PHP_MINOR_VERSION;

		// Do we have the PHP version's data?
		if (isset($phpSupportData[$activePhpVersion]))
		{
			// First check if the version has reached end of support
			$today           = new JDate;
			$phpEndOfSupport = new
JDate($phpSupportData[$activePhpVersion]['eos']);

			if ($phpNotSupported = $today > $phpEndOfSupport)
			{
				/*
				 * Find the oldest PHP version still supported that is newer than the
current version,
				 * this is our recommendation for users on unsupported platforms
				 */
				foreach ($phpSupportData as $version => $versionData)
				{
					$versionEndOfSupport = new JDate($versionData['eos']);

					if (version_compare($version, $activePhpVersion, 'ge')
&& ($today < $versionEndOfSupport))
					{
						$supportStatus['status']  = self::PHP_UNSUPPORTED;
						$supportStatus['message'] = JText::sprintf(
							'PLG_QUICKICON_PHPVERSIONCHECK_UNSUPPORTED',
							PHP_VERSION,
							$version,
							$versionEndOfSupport->format(JText::_('DATE_FORMAT_LC4'))
						);

						return $supportStatus;
					}
				}

				// PHP version is not supported and we don't know of any supported
versions.
				$supportStatus['status']  = self::PHP_UNSUPPORTED;
				$supportStatus['message'] =
JText::sprintf('PLG_QUICKICON_PHPVERSIONCHECK_UNSUPPORTED_JOOMLA_OUTDATED',
PHP_VERSION);

				return $supportStatus;
			}

			// If the version is still supported, check if it has reached eol minus
3 month
			$securityWarningDate = clone $phpEndOfSupport;
			$securityWarningDate->sub(new DateInterval('P3M'));

			if (!$phpNotSupported && $today > $securityWarningDate)
			{
				$supportStatus['status']  = self::PHP_SECURITY_ONLY;
				$supportStatus['message'] = JText::sprintf(
					'PLG_QUICKICON_PHPVERSIONCHECK_SECURITY_ONLY', PHP_VERSION,
$phpEndOfSupport->format(JText::_('DATE_FORMAT_LC4'))
				);
			}
		}

		return $supportStatus;
	}

	/**
	 * Determines if the message should be displayed
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	private function shouldDisplayMessage()
	{
		// Only on admin app
		if (!$this->app->isClient('administrator'))
		{
			return false;
		}

		// Only if authenticated
		if (JFactory::getUser()->guest)
		{
			return false;
		}

		// Only on HTML documents
		if ($this->app->getDocument()->getType() !== 'html')
		{
			return false;
		}

		// Only on full page requests
		if ($this->app->input->getCmd('tmpl',
'index') === 'component')
		{
			return false;
		}

		// Only to com_cpanel
		if ($this->app->input->get('option') !==
'com_cpanel')
		{
			return false;
		}

		return true;
	}
}
quickicon/phpversioncheck/phpversioncheck.xml000064400000001511147357022240015645
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.7" type="plugin"
group="quickicon" method="upgrade">
	<name>plg_quickicon_phpversioncheck</name>
	<author>Joomla! Project</author>
	<creationDate>August 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_QUICKICON_PHPVERSIONCHECK_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="phpversioncheck">phpversioncheck.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_quickicon_phpversioncheck.ini</language>
		<language
tag="en-GB">en-GB.plg_quickicon_phpversioncheck.sys.ini</language>
	</languages>
</extension>
quickicon/privacycheck/privacycheck.php000064400000004624147357022240014404
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Quickicon.privacycheck
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;

/**
 * Plugin to check privacy requests older than 14 days
 *
 * @since  3.9.0
 */
class PlgQuickiconPrivacyCheck extends JPlugin
{
	/**
	 * Load plugin language files automatically
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Check privacy requests older than 14 days.
	 *
	 * @param   string  $context  The calling context
	 *
	 * @return  array   A list of icon definition associative arrays
	 *
	 * @since   3.9.0
	 */
	public function onGetIcons($context)
	{
		if ($context !== $this->params->get('context',
'mod_quickicon') ||
!Factory::getUser()->authorise('core.admin'))
		{
			return;
		}

		JHtml::_('jquery.framework');

		$token    = Session::getFormToken() . '=' . 1;
		$privacy  = 'index.php?option=com_privacy';

		$options  = array(
			'plg_quickicon_privacycheck_url'      => Uri::base() .
$privacy .
'&view=requests&filter[status]=1&list[fullordering]=a.requested_at
ASC',
			'plg_quickicon_privacycheck_ajax_url' => Uri::base() .
$privacy . '&task=getNumberUrgentRequests&' . $token,
			'plg_quickicon_privacycheck_text'     => array(
				"NOREQUEST"            =>
Text::_('PLG_QUICKICON_PRIVACYCHECK_NOREQUEST'),
				"REQUESTFOUND"         =>
Text::_('PLG_QUICKICON_PRIVACYCHECK_REQUESTFOUND'),
				"REQUESTFOUND_MESSAGE" =>
Text::_('PLG_QUICKICON_PRIVACYCHECK_REQUESTFOUND_MESSAGE'),
				"REQUESTFOUND_BUTTON"  =>
Text::_('PLG_QUICKICON_PRIVACYCHECK_REQUESTFOUND_BUTTON'),
				"ERROR"                =>
Text::_('PLG_QUICKICON_PRIVACYCHECK_ERROR'),
			)
		);

		Factory::getDocument()->addScriptOptions('js-privacy-check',
$options);

		JHtml::_('script',
'plg_quickicon_privacycheck/privacycheck.js',
array('version' => 'auto', 'relative'
=> true));

		return array(
			array(
				'link'  => $privacy .
'&view=requests&filter[status]=1&list[fullordering]=a.requested_at
ASC',
				'image' => 'users',
				'icon'  => 'header/icon-48-user.png',
				'text'  =>
Text::_('PLG_QUICKICON_PRIVACYCHECK_CHECKING'),
				'id'    => 'plg_quickicon_privacycheck',
				'group' => 'MOD_QUICKICON_USERS'
			)
		);
	}
}
quickicon/privacycheck/privacycheck.xml000064400000001465147357022240014415
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="quickicon" method="upgrade">
	<name>plg_quickicon_privacycheck</name>
	<author>Joomla! Project</author>
	<creationDate>June 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_QUICKICON_PRIVACYCHECK_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="privacycheck">privacycheck.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_quickicon_privacycheck.ini</language>
		<language
tag="en-GB">en-GB.plg_quickicon_privacycheck.sys.ini</language>
	</languages>
</extension>
sampledata/blog/blog.php000064400000076003147357022240011252
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Sampledata.Blog
 *
 * @copyright   (C) 2017 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Session\Session;

/**
 * Sampledata - Blog Plugin
 *
 * @since  3.8.0
 */
class PlgSampledataBlog extends JPlugin
{
	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 *
	 * @since  3.8.0
	 */
	protected $db;

	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 *
	 * @since  3.8.0
	 */
	protected $app;

	/**
	 * Affects constructor behavior. If true, language files will be loaded
automatically.
	 *
	 * @var    boolean
	 *
	 * @since  3.8.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Holds the menuitem model
	 *
	 * @var    MenusModelItem
	 *
	 * @since  3.8.0
	 */
	private $menuItemModel;

	/**
	 * Get an overview of the proposed sampledata.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since  3.8.0
	 */
	public function onSampledataGetOverview()
	{
		if (!Factory::getUser()->authorise('core.create',
'com_content'))
		{
			return;
		}

		$data              = new stdClass;
		$data->name        = $this->_name;
		$data->title       =
JText::_('PLG_SAMPLEDATA_BLOG_OVERVIEW_TITLE');
		$data->description =
JText::_('PLG_SAMPLEDATA_BLOG_OVERVIEW_DESC');
		$data->icon        = 'broadcast';
		$data->steps       = 3;

		return $data;
	}

	/**
	 * First step to enter the sampledata. Content.
	 *
	 * @return  array or void  Will be converted into the JSON response to the
module.
	 *
	 * @since  3.8.0
	 */
	public function onAjaxSampledataApplyStep1()
	{
		if (!Session::checkToken('get') ||
$this->app->input->get('type') != $this->_name)
		{
			return;
		};

		if (!JComponentHelper::isEnabled('com_content') ||
!Factory::getUser()->authorise('core.create',
'com_content'))
		{
			$response            = array();
			$response['success'] = true;
			$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_SKIPPED', 1,
'com_content');

			return $response;
		}

		// Get some metadata.
		$access = (int) $this->app->get('access', 1);
		$user   = JFactory::getUser();

		// Detect language to be used.
		$language   = Multilanguage::isEnabled() ?
JFactory::getLanguage()->getTag() : '*';
		$langSuffix = ($language !== '*') ? ' (' . $language
. ')' : '';

		// Add Include Paths.
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_content/models/', 'ContentModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_content/tables/');
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_categories/models/',
'CategoriesModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_categories/tables/');

		// Create "blog" category.
		$categoryModel = JModelLegacy::getInstance('Category',
'CategoriesModel');
		$catIds        = array();
		$categoryTitle =
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_CATEGORY_0_TITLE');
		$alias         = JApplicationHelper::stringURLSafe($categoryTitle);

		// Set unicodeslugs if alias is empty
		if (trim(str_replace('-', '', $alias) ==
''))
		{
			$unicode = JFactory::getConfig()->set('unicodeslugs', 1);
			$alias = JApplicationHelper::stringURLSafe($categoryTitle);
			JFactory::getConfig()->set('unicodeslugs', $unicode);
		}

		$category      = array(
			'title'           => $categoryTitle . $langSuffix,
			'parent_id'       => 1,
			'id'              => 0,
			'published'       => 1,
			'access'          => $access,
			'created_user_id' => $user->id,
			'extension'       => 'com_content',
			'level'           => 1,
			'alias'           => $alias . $langSuffix,
			'associations'    => array(),
			'description'     => '',
			'language'        => $language,
			'params'          => '',
		);

		try
		{
			if (!$categoryModel->save($category))
			{
				throw new Exception($categoryModel->getError());
			}
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1,
$e->getMessage());

			return $response;
		}

		// Get ID from category we just added
		$catIds[] = $categoryModel->getItem()->id;

		// Create "help" category.
		$categoryTitle =
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_CATEGORY_1_TITLE');
		$alias         = JApplicationHelper::stringURLSafe($categoryTitle);

		// Set unicodeslugs if alias is empty
		if (trim(str_replace('-', '', $alias) ==
''))
		{
			$unicode = JFactory::getConfig()->set('unicodeslugs', 1);
			$alias = JApplicationHelper::stringURLSafe($categoryTitle);
			JFactory::getConfig()->set('unicodeslugs', $unicode);
		}

		$category      = array(
			'title'           => $categoryTitle . $langSuffix,
			'parent_id'       => 1,
			'id'              => 0,
			'published'       => 1,
			'access'          => $access,
			'created_user_id' => $user->id,
			'extension'       => 'com_content',
			'level'           => 1,
			'alias'           => $alias . $langSuffix,
			'associations'    => array(),
			'description'     => '',
			'language'        => $language,
			'params'          => '',
		);

		try
		{
			if (!$categoryModel->save($category))
			{
				throw new Exception($categoryModel->getError());
			}
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1,
$e->getMessage());

			return $response;
		}

		// Get ID from category we just added
		$catIds[] = $categoryModel->getItem()->id;

		// Create Articles.
		$articleModel = JModelLegacy::getInstance('Article',
'ContentModel');
		$articles     = array(
			array(
				'catid'    => $catIds[1],
				'ordering' => 2,
			),
			array(
				'catid'    => $catIds[1],
				'ordering' => 1,
				'access'   => 3,
			),
			array(
				'catid'    => $catIds[0],
				'ordering' => 2,
			),
			array(
				'catid'    => $catIds[0],
				'ordering' => 1,
			),
			array(
				'catid'    => $catIds[0],
				'ordering' => 0,
			),
			array(
				'catid'    => $catIds[0],
				'ordering' => 0,
			),
		);

		foreach ($articles as $i => $article)
		{
			// Set values from language strings.
			$title                =
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i .
'_TITLE');
			$alias                = JApplicationHelper::stringURLSafe($title);
			$article['title']     = $title . $langSuffix;
			$article['introtext'] =
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i .
'_INTROTEXT');
			$article['fulltext']  =
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i .
'_FULLTEXT');

			// Set values which are always the same.
			$article['id']              = 0;
			$article['created_user_id'] = $user->id;
			$article['alias']           =
JApplicationHelper::stringURLSafe($article['title']);

			// Set unicodeslugs if alias is empty
			if (trim(str_replace('-', '', $alias) ==
''))
			{
				$unicode = JFactory::getConfig()->set('unicodeslugs', 1);
				$article['alias'] =
JApplicationHelper::stringURLSafe($article['title']);
				JFactory::getConfig()->set('unicodeslugs', $unicode);
			}

			$article['language']        = $language;
			$article['associations']    = array();
			$article['state']           = 1;
			$article['featured']        = 0;
			$article['images']          = '';
			$article['metakey']         = '';
			$article['metadesc']        = '';
			$article['xreference']      = '';

			if (!isset($article['access']))
			{
				$article['access'] = $access;
			}

			if (!$articleModel->save($article))
			{
				JFactory::getLanguage()->load('com_content');
				$response            = array();
				$response['success'] = false;
				$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1,
JText::_($articleModel->getError()));

				return $response;
			}

			// Get ID from article we just added
			$ids[] = $articleModel->getItem()->id;
		}

		$this->app->setUserState('sampledata.blog.articles',
$ids);
		$this->app->setUserState('sampledata.blog.articles.catids',
$catIds);

		$response          = new stdClass;
		$response->success = true;
		$response->message =
JText::_('PLG_SAMPLEDATA_BLOG_STEP1_SUCCESS');

		return $response;
	}

	/**
	 * Second step to enter the sampledata. Menus.
	 *
	 * @return  array or void  Will be converted into the JSON response to the
module.
	 *
	 * @since  3.8.0
	 */
	public function onAjaxSampledataApplyStep2()
	{
		if (!Session::checkToken('get') ||
$this->app->input->get('type') != $this->_name)
		{
			return;
		}

		if (!JComponentHelper::isEnabled('com_menus') ||
!Factory::getUser()->authorise('core.create',
'com_menus'))
		{
			$response            = array();
			$response['success'] = true;
			$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_SKIPPED', 2,
'com_menus');

			return $response;
		}

		// Detect language to be used.
		$language   = Multilanguage::isEnabled() ?
JFactory::getLanguage()->getTag() : '*';
		$langSuffix = ($language !== '*') ? ' (' . $language
. ')' : '';

		// Create the menu types.
		$menuTable = JTable::getInstance('Type',
'JTableMenu');
		$menuTypes = array();

		for ($i = 0; $i <= 2; $i++)
		{
			$menu = array(
				'id'          => 0,
				'title'       =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_MENU_' . $i .
'_TITLE') . $langSuffix,
				'description' =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_MENU_' . $i .
'_DESCRIPTION'),
			);

			// Calculate menutype. The number of characters allowed is 24.
			$type = JHtml::_('string.truncate', $menu['title'],
23, true, false);

			$menu['menutype'] = $i . $type;

			try
			{
				$menuTable->load();
				$menuTable->bind($menu);

				if (!$menuTable->check())
				{
					throw new Exception($menuTable->getError());
				}

				$menuTable->store();
			}
			catch (Exception $e)
			{
				JFactory::getLanguage()->load('com_menus');
				$response            = array();
				$response['success'] = false;
				$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2,
$e->getMessage());

				return $response;
			}

			$menuTypes[] = $menuTable->menutype;
		}

		// Storing IDs in UserState for later usage.
		$this->app->setUserState('sampledata.blog.menutypes',
$menuTypes);

		// Get previously entered Data from UserStates.
		$articleIds =
$this->app->getUserState('sampledata.blog.articles');

		// Get MenuItemModel.
		JLoader::register('MenusHelper', JPATH_ADMINISTRATOR .
'/components/com_menus/helpers/menus.php');
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_menus/models/', 'MenusModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_menus/tables/');
		$this->menuItemModel = JModelLegacy::getInstance('Item',
'MenusModel');

		// Get previously entered categories ids
		$catids =
$this->app->getUserState('sampledata.blog.articles.catids');

		// Insert menuitems level 1.
		$menuItems = array(
			array(
				'menutype'     => $menuTypes[0],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_0_TITLE'),
				'link'         =>
'index.php?option=com_content&view=category&layout=blog&id='
. $catids[0],
				'component_id' => 22,
				'params'       => array(
					'layout_type'             => 'blog',
					'show_category_title'     => 0,
					'num_leading_articles'    => 4,
					'num_intro_articles'      => 0,
					'num_columns'             => 1,
					'num_links'               => 2,
					'multi_column_order'      => 1,
					'orderby_sec'             => 'rdate',
					'order_date'              => 'published',
					'show_pagination'         => 2,
					'show_pagination_results' => 1,
					'show_category'           => 0,
					'info_bloc_position'      => 0,
					'show_publish_date'       => 0,
					'show_hits'               => 0,
					'show_feed_link'          => 1,
					'menu_text'               => 1,
					'show_page_heading'       => 0,
					'secure'                  => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[0],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_1_TITLE'),
				'link'         =>
'index.php?option=com_content&view=article&id=' .
$articleIds[0],
				'component_id' => 22,
				'params'       => array(
					'info_block_position' => 0,
					'show_category'       => 0,
					'link_category'       => 0,
					'show_author'         => 0,
					'show_create_date'    => 0,
					'show_publish_date'   => 0,
					'show_hits'           => 0,
					'menu_text'           => 1,
					'show_page_heading'   => 0,
					'secure'              => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[0],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_2_TITLE'),
				'link'         =>
'index.php?option=com_users&view=login',
				'component_id' => 25,
				'params'       => array(
					'logindescription_show'  => 1,
					'logoutdescription_show' => 1,
					'menu_text'              => 1,
					'show_page_heading'      => 0,
					'secure'                 => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_3_TITLE'),
				'link'         =>
'index.php?option=com_content&view=form&layout=edit',
				'component_id' => 22,
				'access'       => 3,
				'params'       => array(
					'enable_category'   => 1,
					'catid'             => $catids[0],
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_4_TITLE'),
				'link'         =>
'index.php?option=com_content&view=article&id=' .
$articleIds[1],
				'component_id' => 22,
				'params'       => array(
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_5_TITLE'),
				'link'         => 'administrator',
				'type'         => 'url',
				'component_id' => 0,
				'browserNav'   => 1,
				'access'       => 3,
				'params'       => array(
					'menu_text' => 1,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_6_TITLE'),
				'link'         =>
'index.php?option=com_users&view=profile&layout=edit',
				'component_id' => 25,
				'access'       => 2,
				'params'       => array(
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_7_TITLE'),
				'link'         =>
'index.php?option=com_users&view=login',
				'component_id' => 25,
				'params'       => array(
					'logindescription_show'  => 1,
					'logoutdescription_show' => 1,
					'menu_text'              => 1,
					'show_page_heading'      => 0,
					'secure'                 => 0,
				),
			),
		);

		try
		{
			$menuIdsLevel1 = $this->addMenuItems($menuItems, 1);
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2,
$e->getMessage());

			return $response;
		}

		// Insert another level 1.
		$menuItems = array(
			array(
				'menutype'     => $menuTypes[2],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_8_TITLE'),
				'link'         =>
'index.php?option=com_users&view=login',
				'component_id' => 25,
				'params'       => array(
					'login_redirect_url'     => 'index.php?Itemid='
. $menuIdsLevel1[0],
					'logindescription_show'  => 1,
					'logoutdescription_show' => 1,
					'menu_text'              => 1,
					'show_page_heading'      => 0,
					'secure'                 => 0,
				),
			),
		);

		try
		{
			$menuIdsLevel1 = array_merge($menuIdsLevel1,
$this->addMenuItems($menuItems, 1));
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2,
$e->getMessage());

			return $response;
		}

		// Insert menuitems level 2.
		$menuItems = array(
			array(
				'menutype'     => $menuTypes[1],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_9_TITLE'),
				'link'         =>
'index.php?option=com_config&view=config&controller=config.display.config',
				'parent_id'    => $menuIdsLevel1[4],
				'component_id' => 23,
				'access'       => 6,
				'params'       => array(
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
			array(
				'menutype'     => $menuTypes[1],
				'title'        =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_10_TITLE'),
				'link'         =>
'index.php?option=com_config&view=templates&controller=config.display.templates',
				'parent_id'    => $menuIdsLevel1[4],
				'component_id' => 23,
				'params'       => array(
					'menu_text'         => 1,
					'show_page_heading' => 0,
					'secure'            => 0,
				),
			),
		);

		try
		{
			$this->addMenuItems($menuItems, 2);
		}
		catch (Exception $e)
		{
			$response            = array();
			$response['success'] = false;
			$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2,
$e->getMessage());

			return $response;
		}

		$response            = array();
		$response['success'] = true;
		$response['message'] =
JText::_('PLG_SAMPLEDATA_BLOG_STEP2_SUCCESS');

		return $response;
	}

	/**
	 * Third step to enter the sampledata. Modules.
	 *
	 * @return  array or void  Will be converted into the JSON response to the
module.
	 *
	 * @since  3.8.0
	 */
	public function onAjaxSampledataApplyStep3()
	{
		if (!Session::checkToken('get') ||
$this->app->input->get('type') != $this->_name)
		{
			return;
		}

		if (!JComponentHelper::isEnabled('com_modules') ||
!Factory::getUser()->authorise('core.create',
'com_modules'))
		{
			$response            = array();
			$response['success'] = true;
			$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_SKIPPED', 3,
'com_modules');

			return $response;
		}

		// Detect language to be used.
		$language   = Multilanguage::isEnabled() ?
JFactory::getLanguage()->getTag() : '*';
		$langSuffix = ($language !== '*') ? ' (' . $language
. ')' : '';

		// Add Include Paths.
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_modules/models/',
'ModulesModelModule');
		JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_modules/tables/');
		$model  = JModelLegacy::getInstance('Module',
'ModulesModel');
		$access = (int) $this->app->get('access', 1);

		// Get previously entered Data from UserStates
		$menuTypes =
$this->app->getUserState('sampledata.blog.menutypes');

		$catids =
$this->app->getUserState('sampledata.blog.articles.catids');

		$modules = array(
			array(
				'title'     =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_0_TITLE'),
				'ordering'  => 1,
				'position'  => 'position-1',
				'module'    => 'mod_menu',
				'showtitle' => 0,
				'params'    => array(
					'menutype'        => $menuTypes[0],
					'startLevel'      => 1,
					'endLevel'        => 0,
					'showAllChildren' => 0,
					'class_sfx'       => ' nav-pills',
					'layout'          => '_:default',
					'cache'           => 1,
					'cache_time'      => 900,
					'cachemode'       => 'itemid',
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'     =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_1_TITLE'),
				'ordering'  => 1,
				'position'  => 'position-1',
				'module'    => 'mod_menu',
				'access'    => 3,
				'showtitle' => 0,
				'params'    => array(
					'menutype'        => $menuTypes[1],
					'startLevel'      => 1,
					'endLevel'        => 0,
					'showAllChildren' => 1,
					'class_sfx'       => ' nav-pills',
					'layout'          => '_:default',
					'cache'           => 1,
					'cache_time'      => 900,
					'cachemode'       => 'itemid',
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'     =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_2_TITLE'),
				'ordering'  => 6,
				'position'  => 'position-7',
				'module'    => 'mod_syndicate',
				'showtitle' => 0,
				'params'    => array(
					'display_text' => 1,
					'text'         => 'My Blog',
					'format'       => 'rss',
					'layout'       => '_:default',
					'cache'        => 0,
				),
			),
			array(
				'title'    =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_3_TITLE'),
				'ordering' => 4,
				'position' => 'position-7',
				'module'   => 'mod_articles_archive',
				'params'   => array(
					'count'      => 10,
					'layout'     => '_:default',
					'cache'      => 1,
					'cache_time' => 900,
					'cachemode'  => 'static',
				),
			),
			array(
				'title'    =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_4_TITLE'),
				'ordering' => 5,
				'position' => 'position-7',
				'module'   => 'mod_articles_popular',
				'params'   => array(
					'catid'      => $catids[0],
					'count'      => 5,
					'show_front' => 1,
					'layout'     => '_:default',
					'cache'      => 1,
					'cache_time' => 900,
					'cachemode'  => 'static',
				),
			),
			array(
				'title'    =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_5_TITLE'),
				'ordering' => 2,
				'position' => 'position-7',
				'module'   => 'mod_articles_category',
				'params'   => array(
					'mode'                         => 'normal',
					'show_on_article_page'         => 0,
					'show_front'                   => 'show',
					'count'                        => 6,
					'category_filtering_type'      => 1,
					'catid'                        => $catids[0],
					'show_child_category_articles' => 0,
					'levels'                       => 1,
					'author_filtering_type'        => 1,
					'author_alias_filtering_type'  => 1,
					'date_filtering'               => 'off',
					'date_field'                   => 'a.created',
					'relative_date'                => 30,
					'article_ordering'             => 'a.created',
					'article_ordering_direction'   => 'DESC',
					'article_grouping'             => 'none',
					'article_grouping_direction'   => 'krsort',
					'month_year_format'            => 'F Y',
					'item_heading'                 => 5,
					'link_titles'                  => 1,
					'show_date'                    => 0,
					'show_date_field'              => 'created',
					'show_date_format'             =>
JText::_('DATE_FORMAT_LC5'),
					'show_category'                => 0,
					'show_hits'                    => 0,
					'show_author'                  => 0,
					'show_introtext'               => 0,
					'introtext_limit'              => 100,
					'show_readmore'                => 0,
					'show_readmore_title'          => 1,
					'readmore_limit'               => 15,
					'layout'                       => '_:default',
					'owncache'                     => 1,
					'cache_time'                   => 900,
					'module_tag'                   => 'div',
					'bootstrap_size'               => 0,
					'header_tag'                   => 'h3',
					'style'                        => 0,
				),
			),
			array(
				'title'     =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_6_TITLE'),
				'ordering'  => 1,
				'position'  => 'footer',
				'module'    => 'mod_menu',
				'showtitle' => 0,
				'params'    => array(
					'menutype'        => $menuTypes[2],
					'startLevel'      => 1,
					'endLevel'        => 0,
					'showAllChildren' => 0,
					'layout'          => '_:default',
					'cache'           => 1,
					'cache_time'      => 900,
					'cachemode'       => 'itemid',
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'    =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_7_TITLE'),
				'ordering' => 1,
				'position' => 'position-0',
				'module'   => 'mod_search',
				'params'   => array(
					'width'      => 20,
					'button_pos' => 'right',
					'opensearch' => 1,
					'layout'     => '_:default',
					'cache'      => 1,
					'cache_time' => 900,
					'cachemode'  => 'itemid',
				),
			),
			array(
				'title'     =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_8_TITLE'),
				'content'   => '<p><img
src="images/headers/raindrops.jpg" alt=""
/></p>',
				'ordering'  => 1,
				'position'  => 'position-3',
				'module'    => 'mod_custom',
				'showtitle' => 0,
				'params'    => array(
					'prepare_content' => 1,
					'layout'          => '_:default',
					'cache'           => 1,
					'cache_time'      => 900,
					'cachemode'       => 'static',
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'    =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_9_TITLE'),
				'ordering' => 1,
				'position' => 'position-7',
				'module'   => 'mod_tags_popular',
				'params'   => array(
					'maximum'         => 8,
					'timeframe'       => 'alltime',
					'order_value'     => 'count',
					'order_direction' => 1,
					'display_count'   => 0,
					'no_results_text' => 0,
					'minsize'         => 1,
					'maxsize'         => 2,
					'layout'          => '_:default',
					'owncache'        => 1,
					'module_tag'      => 'div',
					'bootstrap_size'  => 0,
					'header_tag'      => 'h3',
					'style'           => 0,
				),
			),
			array(
				'title'    =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_10_TITLE'),
				'ordering' => 0,
				'position' => '',
				'module'   => 'mod_tags_similar',
				'params'   => array(
					'maximum'        => 5,
					'matchtype'      => 'any',
					'layout'         => '_:default',
					'owncache'       => 1,
					'module_tag'     => 'div',
					'bootstrap_size' => 0,
					'header_tag'     => 'h3',
					'style'          => 0,
				),
			),
			array(
				'title'     =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_11_TITLE'),
				'ordering'  => 4,
				'position'  => 'cpanel',
				'module'    => 'mod_stats_admin',
				'access'    => 6,
				'client_id' => 1,
				'params'    => array(
					'serverinfo'     => 1,
					'siteinfo'       => 1,
					'counter'        => 0,
					'increase'       => 0,
					'layout'         => '_:default',
					'cache'          => 1,
					'cache_time'     => 900,
					'cachemode'      => 'static',
					'module_tag'     => 'div',
					'bootstrap_size' => 6,
					'header_tag'     => 'h3',
					'style'          => 0,
				),
			),
			array(
				'title'     =>
JText::_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_12_TITLE'),
				'ordering'  => 1,
				'position'  => 'postinstall',
				'module'    => 'mod_feed',
				'client_id' => 1,
				'params'    => array(
					'rssurl'         =>
'https://www.joomla.org/announcements/release-news.feed',
					'rssrtl'         => 0,
					'rsstitle'       => 1,
					'rssdesc'        => 1,
					'rssimage'       => 1,
					'rssitems'       => 3,
					'rssitemdesc'    => 1,
					'word_count'     => 0,
					'layout'         => '_:default',
					'cache'          => 1,
					'cache_time'     => 900,
					'module_tag'     => 'div',
					'bootstrap_size' => 0,
					'header_tag'     => 'h3',
					'style'          => 0,
				),
			),
		);

		foreach ($modules as $module)
		{
			// Append language suffix to title.
			$module['title'] .= $langSuffix;

			// Set values which are always the same.
			$module['id']         = 0;
			$module['asset_id']   = 0;
			$module['language']   = $language;
			$module['note']       = '';
			$module['published']  = 1;
			$module['assignment'] = 0;

			if (!isset($module['content']))
			{
				$module['content'] = '';
			}

			if (!isset($module['access']))
			{
				$module['access'] = $access;
			}

			if (!isset($module['showtitle']))
			{
				$module['showtitle'] = 1;
			}

			if (!isset($module['client_id']))
			{
				$module['client_id'] = 0;
			}

			if (!$model->save($module))
			{
				JFactory::getLanguage()->load('com_modules');
				$response            = array();
				$response['success'] = false;
				$response['message'] =
JText::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 3,
JText::_($model->getError()));

				return $response;
			}
		}

		$response            = array();
		$response['success'] = true;
		$response['message'] =
JText::_('PLG_SAMPLEDATA_BLOG_STEP3_SUCCESS');

		return $response;
	}

	/**
	 * Adds menuitems.
	 *
	 * @param   array    $menuItems  Array holding the menuitems arrays.
	 * @param   integer  $level      Level in the category tree.
	 *
	 * @return  array  IDs of the inserted menuitems.
	 *
	 * @since  3.8.0
	 *
	 * @throws  Exception
	 */
	private function addMenuItems(array $menuItems, $level)
	{
		$itemIds = array();
		$access  = (int) $this->app->get('access', 1);
		$user    = JFactory::getUser();

		// Detect language to be used.
		$language   = Multilanguage::isEnabled() ?
JFactory::getLanguage()->getTag() : '*';
		$langSuffix = ($language !== '*') ? ' (' . $language
. ')' : '';

		foreach ($menuItems as $menuItem)
		{
			// Reset item.id in model state.
			$this->menuItemModel->setState('item.id', 0);

			// Set values which are always the same.
			$menuItem['id']              = 0;
			$menuItem['created_user_id'] = $user->id;
			$menuItem['alias']           =
JApplicationHelper::stringURLSafe($menuItem['title']);

			// Set unicodeslugs if alias is empty
			if (trim(str_replace('-', '',
$menuItem['alias']) == ''))
			{
				$unicode = JFactory::getConfig()->set('unicodeslugs', 1);
				$menuItem['alias'] =
JApplicationHelper::stringURLSafe($menuItem['title']);
				JFactory::getConfig()->set('unicodeslugs', $unicode);
			}

			// Append language suffix to title.
			$menuItem['title'] .= $langSuffix;

			$menuItem['published']       = 1;
			$menuItem['language']        = $language;
			$menuItem['note']            = '';
			$menuItem['img']             = '';
			$menuItem['associations']    = array();
			$menuItem['client_id']       = 0;
			$menuItem['level']           = $level;
			$menuItem['home']            = 0;

			// Set browserNav to default if not set
			if (!isset($menuItem['browserNav']))
			{
				$menuItem['browserNav'] = 0;
			}

			// Set access to default if not set
			if (!isset($menuItem['access']))
			{
				$menuItem['access'] = $access;
			}

			// Set type to 'component' if not set
			if (!isset($menuItem['type']))
			{
				$menuItem['type'] = 'component';
			}

			// Set template_style_id to global if not set
			if (!isset($menuItem['template_style_id']))
			{
				$menuItem['template_style_id'] = 0;
			}

			// Set parent_id to root (1) if not set
			if (!isset($menuItem['parent_id']))
			{
				$menuItem['parent_id'] = 1;
			}

			if (!$this->menuItemModel->save($menuItem))
			{
				// Try two times with another alias (-1 and -2).
				$menuItem['alias'] .= '-1';

				if (!$this->menuItemModel->save($menuItem))
				{
					$menuItem['alias'] =
substr_replace($menuItem['alias'], '2', -1);

					if (!$this->menuItemModel->save($menuItem))
					{
						throw new Exception($menuItem['title'] . ' =>
' . $menuItem['alias'] . ' : ' .
$this->menuItemModel->getError());
					}
				}
			}

			// Get ID from menuitem we just added
			$itemIds[] = $this->menuItemModel->getstate('item.id');
		}

		return $itemIds;
	}
}
sampledata/blog/blog.xml000064400000001504147357022240011255
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin"
group="sampledata" method="upgrade">
	<name>plg_sampledata_blog</name>
	<author>Joomla! Project</author>
	<creationDate>July 2017</creationDate>
	<copyright>(C) 2017 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.8.0</version>
	<description>PLG_SAMPLEDATA_BLOG_XML_DESCRIPTION</description>
	<files>
		<filename plugin="blog">blog.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_sampledata_blog.ini</language>
		<language
tag="en-GB">en-GB.plg_sampledata_blog.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
		</fields>
	</config>
</extension>
search/categories/categories.php000064400000011604147357022240013004
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Search.categories
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('ContentHelperRoute', JPATH_SITE .
'/components/com_content/helpers/route.php');

/**
 * Categories search plugin.
 *
 * @since  1.6
 */
class PlgSearchCategories extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   1.6
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'categories' =>
'PLG_SEARCH_CATEGORIES_CATEGORIES'
		);

		return $areas;
	}

	/**
	 * Search content (categories).
	 *
	 * The SQL must return the following fields that are used in a common
display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values:
exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values:
newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   mixed   $areas     An array if the search is to be restricted
to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   1.6
	 */
	public function onContentSearch($text, $phrase = '', $ordering =
'', $areas = null)
	{
		$db = JFactory::getDbo();
		$user = JFactory::getUser();
		$app = JFactory::getApplication();
		$groups = implode(',', $user->getAuthorisedViewLevels());
		$searchText = $text;

		if (is_array($areas) && !array_intersect($areas,
array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$sContent = $this->params->get('search_content', 1);
		$sArchived = $this->params->get('search_archived', 1);
		$limit = $this->params->def('search_limit', 50);
		$state = array();

		if ($sContent)
		{
			$state[] = 1;
		}

		if ($sArchived)
		{
			$state[] = 2;
		}

		if (empty($state))
		{
			return array();
		}

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		/* TODO: The $where variable does not seem to be used at all
		switch ($phrase)
		{
			case 'exact':
				$text = $db->quote('%' . $db->escape($text, true) .
'%', false);
				$wheres2 = array();
				$wheres2[] = 'a.title LIKE ' . $text;
				$wheres2[] = 'a.description LIKE ' . $text;
				$where = '(' . implode(') OR (', $wheres2) .
')';
				break;

			case 'any':
			case 'all';
			default:
				$words = explode(' ', $text);
				$wheres = array();
				foreach ($words as $word)
				{
					$word = $db->quote('%' . $db->escape($word, true) .
'%', false);
					$wheres2 = array();
					$wheres2[] = 'a.title LIKE ' . $word;
					$wheres2[] = 'a.description LIKE ' . $word;
					$wheres[] = implode(' OR ', $wheres2);
				}
				$where = '(' . implode(($phrase == 'all' ? ')
AND (' : ') OR ('), $wheres) . ')';
				break;
		}
		*/

		switch ($ordering)
		{
			case 'alpha':
				$order = 'a.title ASC';
				break;

			case 'category':
			case 'popular':
			case 'newest':
			case 'oldest':
			default:
				$order = 'a.title DESC';
		}

		$text = $db->quote('%' . $db->escape($text, true) .
'%', false);
		$query = $db->getQuery(true);

		// SQLSRV changes.
		$case_when = ' CASE WHEN ';
		$case_when .= $query->charLength('a.alias', '!=',
'0');
		$case_when .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when .= $query->concatenate(array($a_id, 'a.alias'),
':');
		$case_when .= ' ELSE ';
		$case_when .= $a_id . ' END as slug';
		$query->select('a.title, a.description AS text, a.created_time AS
created, \'2\' AS browsernav, a.id AS catid, ' . $case_when)
			->from('#__categories AS a')
			->where(
				'(a.title LIKE ' . $text . ' OR a.description LIKE
' . $text . ') AND a.published IN (' .
implode(',', $state) . ') AND a.extension = '
				. $db->quote('com_content') . 'AND a.access IN
(' . $groups . ')'
			)
			->group('a.id, a.title, a.description, a.alias,
a.created_time')
			->order($order);

		if ($app->isClient('site') &&
JLanguageMultilang::isEnabled())
		{
			$query->where('a.language in (' .
$db->quote(JFactory::getLanguage()->getTag()) . ',' .
$db->quote('*') . ')');
		}

		$db->setQuery($query, 0, $limit);

		try
		{
			$rows = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$rows = array();
			JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'),
'error');
		}

		$return = array();

		if ($rows)
		{
			foreach ($rows as $i => $row)
			{
				if (searchHelper::checkNoHtml($row, $searchText,
array('name', 'title', 'text')))
				{
					$row->href = ContentHelperRoute::getCategoryRoute($row->slug);
					$row->section = JText::_('JCATEGORY');

					$return[] = $row;
				}
			}
		}

		return $return;
	}
}
search/categories/categories.xml000064400000003340147357022240013013
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="search" method="upgrade">
	<name>plg_search_categories</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_CATEGORIES_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="categories">categories.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_search_categories.ini</language>
		<language
tag="en-GB">en-GB.plg_search_categories.sys.ini</language>
	</languages>
	<config>
		<fields name="params">

			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="JFIELD_PLG_SEARCH_SEARCHLIMIT_LABEL"
					description="JFIELD_PLG_SEARCH_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="search_content"
					type="radio"
					label="JFIELD_PLG_SEARCH_ALL_LABEL"
					description="JFIELD_PLG_SEARCH_ALL_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="search_archived"
					type="radio"
					label="JFIELD_PLG_SEARCH_ARCHIVED_LABEL"
					description="JFIELD_PLG_SEARCH_ARCHIVED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>

		</fields>
	</config>
</extension>
search/contacts/contacts.php000064400000012067147357022240012172
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Search.contacts
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Contacts search plugin.
 *
 * @since  1.6
 */
class PlgSearchContacts extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   1.6
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'contacts' => 'PLG_SEARCH_CONTACTS_CONTACTS'
		);

		return $areas;
	}

	/**
	 * Search content (contacts).
	 *
	 * The SQL must return the following fields that are used in a common
display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values:
exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values:
newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   string  $areas     An array if the search is to be restricted
to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   1.6
	 */
	public function onContentSearch($text, $phrase = '', $ordering =
'', $areas = null)
	{
		JLoader::register('ContactHelperRoute', JPATH_SITE .
'/components/com_contact/helpers/route.php');

		$db     = JFactory::getDbo();
		$app    = JFactory::getApplication();
		$user   = JFactory::getUser();
		$groups = implode(',', $user->getAuthorisedViewLevels());

		if (is_array($areas) && !array_intersect($areas,
array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$sContent  = $this->params->get('search_content', 1);
		$sArchived = $this->params->get('search_archived', 1);
		$limit     = $this->params->def('search_limit', 50);
		$state     = array();

		if ($sContent)
		{
			$state[] = 1;
		}

		if ($sArchived)
		{
			$state[] = 2;
		}

		if (empty($state))
		{
			return array();
		}

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		$section = JText::_('PLG_SEARCH_CONTACTS_CONTACTS');

		switch ($ordering)
		{
			case 'alpha':
				$order = 'a.name ASC';
				break;

			case 'category':
				$order = 'c.title ASC, a.name ASC';
				break;

			case 'popular':
			case 'newest':
			case 'oldest':
			default:
				$order = 'a.name DESC';
		}

		$text = $db->quote('%' . $db->escape($text, true) .
'%', false);

		$query = $db->getQuery(true);

		// SQLSRV changes.
		$case_when  = ' CASE WHEN ';
		$case_when .= $query->charLength('a.alias', '!=',
'0');
		$case_when .= ' THEN ';
		$a_id = $query->castAsChar('a.id');
		$case_when .= $query->concatenate(array($a_id, 'a.alias'),
':');
		$case_when .= ' ELSE ';
		$case_when .= $a_id . ' END as slug';

		$case_when1  = ' CASE WHEN ';
		$case_when1 .= $query->charLength('c.alias', '!=',
'0');
		$case_when1 .= ' THEN ';
		$c_id        = $query->castAsChar('c.id');
		$case_when1 .= $query->concatenate(array($c_id, 'c.alias'),
':');
		$case_when1 .= ' ELSE ';
		$case_when1 .= $c_id . ' END as catslug';

		$query->select(
			'a.name AS title, \'\' AS created, a.con_position,
a.misc, '
				. $case_when . ',' . $case_when1 . ', '
				. $query->concatenate(array('a.name',
'a.con_position', 'a.misc'), ',') . ' AS
text,'
				. $query->concatenate(array($db->quote($section),
'c.title'), ' / ') . ' AS section,'
				. '\'2\' AS browsernav'
		);
		$query->from('#__contact_details AS a')
			->join('INNER', '#__categories AS c ON c.id =
a.catid')
			->where(
				'(a.name LIKE ' . $text . ' OR a.misc LIKE ' .
$text . ' OR a.con_position LIKE ' . $text
					. ' OR a.address LIKE ' . $text . ' OR a.suburb LIKE
' . $text . ' OR a.state LIKE ' . $text
					. ' OR a.country LIKE ' . $text . ' OR a.postcode LIKE
' . $text . ' OR a.telephone LIKE ' . $text
					. ' OR a.fax LIKE ' . $text . ') AND a.published IN
(' . implode(',', $state) . ') AND c.published=1 '
					. ' AND a.access IN (' . $groups . ') AND c.access IN
(' . $groups . ')'
			)
			->order($order);

		// Filter by language.
		if ($app->isClient('site') &&
JLanguageMultilang::isEnabled())
		{
			$tag = JFactory::getLanguage()->getTag();
			$query->where('a.language in (' . $db->quote($tag) .
',' . $db->quote('*') . ')')
				->where('c.language in (' . $db->quote($tag) .
',' . $db->quote('*') . ')');
		}

		$db->setQuery($query, 0, $limit);

		try
		{
			$rows = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$rows = array();
			JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'),
'error');
		}

		if ($rows)
		{
			foreach ($rows as $key => $row)
			{
				$rows[$key]->href  =
ContactHelperRoute::getContactRoute($row->slug, $row->catslug);
				$rows[$key]->text  = $row->title;
				$rows[$key]->text .= $row->con_position ? ', ' .
$row->con_position : '';
				$rows[$key]->text .= $row->misc ? ', ' . $row->misc
: '';
			}
		}

		return $rows;
	}
}
search/contacts/contacts.xml000064400000003322147357022240012175
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="search" method="upgrade">
	<name>plg_search_contacts</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_CONTACTS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="contacts">contacts.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_search_contacts.ini</language>
		<language
tag="en-GB">en-GB.plg_search_contacts.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="JFIELD_PLG_SEARCH_SEARCHLIMIT_LABEL"
					description="JFIELD_PLG_SEARCH_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="search_content"
					type="radio"
					label="JFIELD_PLG_SEARCH_ALL_LABEL"
					description="JFIELD_PLG_SEARCH_ALL_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="search_archived"
					type="radio"
					label="JFIELD_PLG_SEARCH_ARCHIVED_LABEL"
					description="JFIELD_PLG_SEARCH_ARCHIVED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
search/content/content.php000064400000032177147357022240011666
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Search.content
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Content search plugin.
 *
 * @since  1.6
 */
class PlgSearchContent extends JPlugin
{
	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   1.6
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'content' => 'JGLOBAL_ARTICLES'
		);

		return $areas;
	}

	/**
	 * Search content (articles).
	 * The SQL must return the following fields that are used in a common
display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values:
exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values:
newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   mixed   $areas     An array if the search it to be restricted
to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   1.6
	 */
	public function onContentSearch($text, $phrase = '', $ordering =
'', $areas = null)
	{
		$db         = JFactory::getDbo();
		$serverType = $db->getServerType();
		$app        = JFactory::getApplication();
		$user       = JFactory::getUser();
		$groups     = implode(',',
$user->getAuthorisedViewLevels());
		$tag        = JFactory::getLanguage()->getTag();

		JLoader::register('ContentHelperRoute', JPATH_SITE .
'/components/com_content/helpers/route.php');
		JLoader::register('SearchHelper', JPATH_ADMINISTRATOR .
'/components/com_search/helpers/search.php');

		$searchText = $text;

		if (is_array($areas) && !array_intersect($areas,
array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$sContent  = $this->params->get('search_content', 1);
		$sArchived = $this->params->get('search_archived', 1);
		$limit     = $this->params->def('search_limit', 50);

		$nullDate  = $db->getNullDate();
		$date      = JFactory::getDate();
		$now       = $date->toSql();

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		switch ($phrase)
		{
			case 'exact':
				$text      = $db->quote('%' . $db->escape($text, true)
. '%', false);
				$wheres2   = array();
				$wheres2[] = 'a.title LIKE ' . $text;
				$wheres2[] = 'a.introtext LIKE ' . $text;
				$wheres2[] = 'a.fulltext LIKE ' . $text;
				$wheres2[] = 'a.metakey LIKE ' . $text;
				$wheres2[] = 'a.metadesc LIKE ' . $text;

				$relevance[] = ' CASE WHEN ' . $wheres2[0] . ' THEN 5
ELSE 0 END ';

				// Join over Fields.
				$subQuery = $db->getQuery(true);
				$subQuery->select("cfv.item_id")
					->from("#__fields_values AS cfv")
					->join('LEFT', '#__fields AS f ON f.id =
cfv.field_id')
					->where('(f.context IS NULL OR f.context = ' .
$db->q('com_content.article') . ')')
					->where('(f.state IS NULL OR f.state = 1)')
					->where('(f.access IS NULL OR f.access IN (' . $groups .
'))')
					->where('cfv.value LIKE ' . $text);

				// Filter by language.
				if ($app->isClient('site') &&
JLanguageMultilang::isEnabled())
				{
					$subQuery->where('(f.language IS NULL OR f.language in ('
. $db->quote($tag) . ',' . $db->quote('*') .
'))');
				}

				if ($serverType == "mysql")
				{
					/* This generates a dependent sub-query so do no use in MySQL prior to
version 6.0 !
					* $wheres2[] = 'a.id IN( '. (string)
$subQuery.')';
					*/

					$db->setQuery($subQuery);
					$fieldids = $db->loadColumn();

					if (count($fieldids))
					{
						$wheres2[] = 'a.id IN(' . implode(",", $fieldids)
. ')';
					}
				}
				else
				{
					$wheres2[] = $subQuery->castAsChar('a.id') . ' IN(
' . (string) $subQuery . ')';
				}

				$where = '(' . implode(') OR (', $wheres2) .
')';
				break;

			case 'all':
			case 'any':
			default:
				$words = explode(' ', $text);
				$wheres = array();
				$cfwhere = array();

				foreach ($words as $word)
				{
					$word      = $db->quote('%' . $db->escape($word, true)
. '%', false);
					$wheres2   = array();
					$wheres2[] = 'LOWER(a.title) LIKE LOWER(' . $word .
')';
					$wheres2[] = 'LOWER(a.introtext) LIKE LOWER(' . $word .
')';
					$wheres2[] = 'LOWER(a.fulltext) LIKE LOWER(' . $word .
')';
					$wheres2[] = 'LOWER(a.metakey) LIKE LOWER(' . $word .
')';
					$wheres2[] = 'LOWER(a.metadesc) LIKE LOWER(' . $word .
')';

					$relevance[] = ' CASE WHEN ' . $wheres2[0] . ' THEN 5
ELSE 0 END ';

					if ($phrase === 'all')
					{
						// Join over Fields.
						$subQuery = $db->getQuery(true);
						$subQuery->select("cfv.item_id")
							->from("#__fields_values AS cfv")
							->join('LEFT', '#__fields AS f ON f.id =
cfv.field_id')
							->where('(f.context IS NULL OR f.context = ' .
$db->q('com_content.article') . ')')
							->where('(f.state IS NULL OR f.state = 1)')
							->where('(f.access IS NULL OR f.access IN (' . $groups
. '))')
							->where('LOWER(cfv.value) LIKE LOWER(' . $word .
')');

						// Filter by language.
						if ($app->isClient('site') &&
JLanguageMultilang::isEnabled())
						{
							$subQuery->where('(f.language IS NULL OR f.language in
(' . $db->quote($tag) . ',' .
$db->quote('*') . '))');
						}

						if ($serverType == "mysql")
						{
							$db->setQuery($subQuery);
							$fieldids = $db->loadColumn();

							if (count($fieldids))
							{
								$wheres2[] = 'a.id IN(' . implode(",",
$fieldids) . ')';
							}
						}
						else
						{
							$wheres2[] = $subQuery->castAsChar('a.id') . ' IN(
' . (string) $subQuery . ')';
						}
					}
					else
					{
						$cfwhere[] = 'LOWER(cfv.value) LIKE LOWER(' . $word .
')';
					}

					$wheres[] = implode(' OR ', $wheres2);
				}

				if ($phrase === 'any')
				{
					// Join over Fields.
					$subQuery = $db->getQuery(true);
					$subQuery->select("cfv.item_id")
						->from("#__fields_values AS cfv")
						->join('LEFT', '#__fields AS f ON f.id =
cfv.field_id')
						->where('(f.context IS NULL OR f.context = ' .
$db->q('com_content.article') . ')')
						->where('(f.state IS NULL OR f.state = 1)')
						->where('(f.access IS NULL OR f.access IN (' . $groups .
'))')
						->where('(' . implode(($phrase === 'all' ?
') AND (' : ') OR ('), $cfwhere) . ')');

					// Filter by language.
					if ($app->isClient('site') &&
JLanguageMultilang::isEnabled())
					{
						$subQuery->where('(f.language IS NULL OR f.language in
(' . $db->quote($tag) . ',' .
$db->quote('*') . '))');
					}

					if ($serverType == "mysql")
					{
						$db->setQuery($subQuery);
						$fieldids = $db->loadColumn();

						if (count($fieldids))
						{
							$wheres[] = 'a.id IN(' . implode(",", $fieldids)
. ')';
						}
					}
					else
					{
						$wheres[] = $subQuery->castAsChar('a.id') . ' IN(
' . (string) $subQuery . ')';
					}
				}

				$where = '(' . implode(($phrase === 'all' ? ')
AND (' : ') OR ('), $wheres) . ')';
				break;
		}

		switch ($ordering)
		{
			case 'oldest':
				$order = 'a.created ASC';
				break;

			case 'popular':
				$order = 'a.hits DESC';
				break;

			case 'alpha':
				$order = 'a.title ASC';
				break;

			case 'category':
				$order = 'c.title ASC, a.title ASC';
				break;

			case 'newest':
			default:
				$order = 'a.created DESC';
				break;
		}

		$rows = array();
		$query = $db->getQuery(true);

		// Search articles.
		if ($sContent && $limit > 0)
		{
			$query->clear();

			// SQLSRV changes.
			$case_when  = ' CASE WHEN ';
			$case_when .= $query->charLength('a.alias', '!=',
'0');
			$case_when .= ' THEN ';
			$a_id       = $query->castAsChar('a.id');
			$case_when .= $query->concatenate(array($a_id, 'a.alias'),
':');
			$case_when .= ' ELSE ';
			$case_when .= $a_id . ' END as slug';

			$case_when1  = ' CASE WHEN ';
			$case_when1 .= $query->charLength('c.alias',
'!=', '0');
			$case_when1 .= ' THEN ';
			$c_id        = $query->castAsChar('c.id');
			$case_when1 .= $query->concatenate(array($c_id, 'c.alias'),
':');
			$case_when1 .= ' ELSE ';
			$case_when1 .= $c_id . ' END as catslug';

			if (!empty($relevance))
			{
				$query->select(implode(' + ', $relevance) . ' AS
relevance');
				$order = ' relevance DESC, ' . $order;
			}

			$query->select('a.title AS title, a.metadesc, a.metakey,
a.created AS created, a.language, a.catid')
				->select($query->concatenate(array('a.introtext',
'a.fulltext')) . ' AS text')
				->select('c.title AS section, ' . $case_when .
',' . $case_when1 . ', ' . '\'2\' AS
browsernav')
				->from('#__content AS a')
				->join('INNER', '#__categories AS c ON
c.id=a.catid')
				->where(
					'(' . $where . ') AND a.state=1 AND c.published = 1 AND
a.access IN (' . $groups . ') '
						. 'AND c.access IN (' . $groups . ')'
						. 'AND (a.publish_up = ' . $db->quote($nullDate) .
' OR a.publish_up <= ' . $db->quote($now) . ') '
						. 'AND (a.publish_down = ' . $db->quote($nullDate) .
' OR a.publish_down >= ' . $db->quote($now) . ')'
				)
				->group('a.id, a.title, a.metadesc, a.metakey, a.created,
a.language, a.catid, a.introtext, a.fulltext, c.title, a.alias, c.alias,
c.id')
				->order($order);

			// Filter by language.
			if ($app->isClient('site') &&
JLanguageMultilang::isEnabled())
			{
				$query->where('a.language in (' . $db->quote($tag) .
',' . $db->quote('*') . ')')
					->where('c.language in (' . $db->quote($tag) .
',' . $db->quote('*') . ')');
			}

			$db->setQuery($query, 0, $limit);

			try
			{
				$list = $db->loadObjectList();
			}
			catch (RuntimeException $e)
			{
				$list = array();
				JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'),
'error');
			}

			$limit -= count($list);

			if (isset($list))
			{
				foreach ($list as $key => $item)
				{
					$list[$key]->href =
ContentHelperRoute::getArticleRoute($item->slug, $item->catid,
$item->language);
				}
			}

			$rows[] = $list;
		}

		// Search archived content.
		if ($sArchived && $limit > 0)
		{
			$query->clear();

			// SQLSRV changes.
			$case_when  = ' CASE WHEN ';
			$case_when .= $query->charLength('a.alias', '!=',
'0');
			$case_when .= ' THEN ';
			$a_id       = $query->castAsChar('a.id');
			$case_when .= $query->concatenate(array($a_id, 'a.alias'),
':');
			$case_when .= ' ELSE ';
			$case_when .= $a_id . ' END as slug';

			$case_when1  = ' CASE WHEN ';
			$case_when1 .= $query->charLength('c.alias',
'!=', '0');
			$case_when1 .= ' THEN ';
			$c_id        = $query->castAsChar('c.id');
			$case_when1 .= $query->concatenate(array($c_id, 'c.alias'),
':');
			$case_when1 .= ' ELSE ';
			$case_when1 .= $c_id . ' END as catslug';

			if (!empty($relevance))
			{
				$query->select(implode(' + ', $relevance) . ' AS
relevance');
				$order = ' relevance DESC, ' . $order;
			}

			$query->select('a.title AS title, a.metadesc, a.metakey,
a.created AS created, a.language, a.catid')
				->select($query->concatenate(array('a.introtext',
'a.fulltext')) . ' AS text')
				->select('c.title AS section, ' . $case_when .
',' . $case_when1 . ', ' . '\'2\' AS
browsernav')
				->from('#__content AS a')
				->join('INNER', '#__categories AS c ON c.id=a.catid
AND c.access IN (' . $groups . ')')
				->where(
					'(' . $where . ') AND a.state = 2 AND c.published = 1
AND a.access IN (' . $groups
						. ') AND c.access IN (' . $groups . ') '
						. 'AND (a.publish_up = ' . $db->quote($nullDate) .
' OR a.publish_up <= ' . $db->quote($now) . ') '
						. 'AND (a.publish_down = ' . $db->quote($nullDate) .
' OR a.publish_down >= ' . $db->quote($now) . ')'
				)
				->order($order);

			// Join over Fields is no longer needed

			// Filter by language.
			if ($app->isClient('site') &&
JLanguageMultilang::isEnabled())
			{
				$query->where('a.language in (' . $db->quote($tag) .
',' . $db->quote('*') . ')')
					->where('c.language in (' . $db->quote($tag) .
',' . $db->quote('*') . ')');
			}

			$db->setQuery($query, 0, $limit);

			try
			{
				$list3 = $db->loadObjectList();
			}
			catch (RuntimeException $e)
			{
				$list3 = array();
				JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'),
'error');
			}

			if (isset($list3))
			{
				foreach ($list3 as $key => $item)
				{
					$list3[$key]->href =
ContentHelperRoute::getArticleRoute($item->slug, $item->catid,
$item->language);
				}
			}

			$rows[] = $list3;
		}

		$results = array();

		if (count($rows))
		{
			foreach ($rows as $row)
			{
				$new_row = array();

				foreach ($row as $article)
				{
					// Not efficient to get these ONE article at a TIME
					// Lookup field values so they can be checked, GROUP_CONCAT would work
in above queries, but isn't supported by non-MySQL DBs.
					$query = $db->getQuery(true);
					$query->select('fv.value')
						->from('#__fields_values as fv')
						->join('left', '#__fields as f on fv.field_id =
f.id')
						->where('f.context = ' .
$db->quote('com_content.article'))
						->where('fv.item_id = ' . $db->quote((int)
$article->slug));
					$db->setQuery($query);
					$article->jcfields = implode(',', $db->loadColumn());

					if (SearchHelper::checkNoHtml($article, $searchText,
array('text', 'title', 'jcfields',
'metadesc', 'metakey')))
					{
						$new_row[] = $article;
					}
				}

				$results = array_merge($results, (array) $new_row);
			}
		}

		return $results;
	}

}
search/content/content.xml000064400000003377147357022240011677
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="search" method="upgrade">
	<name>plg_search_content</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_CONTENT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="content">content.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_search_content.ini</language>
		<language
tag="en-GB">en-GB.plg_search_content.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="PLG_SEARCH_CONTENT_FIELD_SEARCHLIMIT_LABEL"
					description="PLG_SEARCH_CONTENT_FIELD_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="search_content"
					type="radio"
					label="PLG_SEARCH_CONTENT_FIELD_CONTENT_LABEL"
					description="PLG_SEARCH_CONTENT_FIELD_CONTENT_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="search_archived"
					type="radio"
					label="PLG_SEARCH_CONTENT_FIELD_ARCHIVED_LABEL"
					description="PLG_SEARCH_CONTENT_FIELD_ARCHIVED_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>

		</fields>
	</config>
</extension>
search/newsfeeds/newsfeeds.php000064400000012022147357022240012473
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Search.newsfeeds
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Newsfeeds search plugin.
 *
 * @since  1.6
 */
class PlgSearchNewsfeeds extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   1.6
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'newsfeeds' => 'PLG_SEARCH_NEWSFEEDS_NEWSFEEDS'
		);

		return $areas;
	}

	/**
	 * Search content (newsfeeds).
	 *
	 * The SQL must return the following fields that are used in a common
display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values:
exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values:
newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   mixed   $areas     An array if the search it to be restricted
to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   1.6
	 */
	public function onContentSearch($text, $phrase = '', $ordering =
'', $areas = null)
	{
		$db = JFactory::getDbo();
		$app = JFactory::getApplication();
		$user = JFactory::getUser();
		$groups = implode(',', $user->getAuthorisedViewLevels());

		if (is_array($areas) && !array_intersect($areas,
array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$sContent = $this->params->get('search_content', 1);
		$sArchived = $this->params->get('search_archived', 1);
		$limit = $this->params->def('search_limit', 50);
		$state = array();

		if ($sContent)
		{
			$state[] = 1;
		}

		if ($sArchived)
		{
			$state[] = 2;
		}

		if (empty($state))
		{
			return array();
		}

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		switch ($phrase)
		{
			case 'exact':
				$text = $db->quote('%' . $db->escape($text, true) .
'%', false);
				$wheres2 = array();
				$wheres2[] = 'a.name LIKE ' . $text;
				$wheres2[] = 'a.link LIKE ' . $text;
				$where = '(' . implode(') OR (', $wheres2) .
')';
				break;

			case 'all':
			case 'any':
			default:
				$words = explode(' ', $text);
				$wheres = array();

				foreach ($words as $word)
				{
					$word = $db->quote('%' . $db->escape($word, true) .
'%', false);
					$wheres2 = array();
					$wheres2[] = 'a.name LIKE ' . $word;
					$wheres2[] = 'a.link LIKE ' . $word;
					$wheres[] = implode(' OR ', $wheres2);
				}

				$where = '(' . implode(($phrase === 'all' ? ')
AND (' : ') OR ('), $wheres) . ')';
				break;
		}

		switch ($ordering)
		{
			case 'alpha':
				$order = 'a.name ASC';
				break;

			case 'category':
				$order = 'c.title ASC, a.name ASC';
				break;

			case 'oldest':
			case 'popular':
			case 'newest':
			default:
				$order = 'a.name ASC';
		}

		$searchNewsfeeds = JText::_('PLG_SEARCH_NEWSFEEDS_NEWSFEEDS');

		$query = $db->getQuery(true);

		// SQLSRV changes.
		$case_when  = ' CASE WHEN ';
		$case_when .= $query->charLength('a.alias', '!=',
'0');
		$case_when .= ' THEN ';
		$a_id       = $query->castAsChar('a.id');
		$case_when .= $query->concatenate(array($a_id, 'a.alias'),
':');
		$case_when .= ' ELSE ';
		$case_when .= $a_id . ' END as slug';

		$case_when1  = ' CASE WHEN ';
		$case_when1 .= $query->charLength('c.alias', '!=',
'0');
		$case_when1 .= ' THEN ';
		$c_id        = $query->castAsChar('c.id');
		$case_when1 .= $query->concatenate(array($c_id, 'c.alias'),
':');
		$case_when1 .= ' ELSE ';
		$case_when1 .= $c_id . ' END as catslug';

		$query->select('a.name AS title, \'\' AS created,
a.link AS text, ' . $case_when . ',' . $case_when1)
			->select($query->concatenate(array($db->quote($searchNewsfeeds),
'c.title'), ' / ') . ' AS section')
			->select('\'1\' AS browsernav')
			->from('#__newsfeeds AS a')
			->join('INNER', '#__categories as c ON c.id =
a.catid')
			->where('(' . $where . ') AND a.published IN (' .
implode(',', $state) . ') AND c.published = 1 AND c.access
IN (' . $groups . ')')
			->order($order);

		// Filter by language.
		if ($app->isClient('site') &&
JLanguageMultilang::isEnabled())
		{
			$tag = JFactory::getLanguage()->getTag();
			$query->where('a.language in (' . $db->quote($tag) .
',' . $db->quote('*') . ')')
				->where('c.language in (' . $db->quote($tag) .
',' . $db->quote('*') . ')');
		}

		$db->setQuery($query, 0, $limit);

		try
		{
			$rows = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$rows = array();
			JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'),
'error');
		}

		if ($rows)
		{
			foreach ($rows as $key => $row)
			{
				$rows[$key]->href =
'index.php?option=com_newsfeeds&view=newsfeed&catid=' .
$row->catslug . '&id=' . $row->slug;
			}
		}

		return $rows;
	}
}
search/newsfeeds/newsfeeds.xml000064400000003330147357022240012506
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="search" method="upgrade">
	<name>plg_search_newsfeeds</name>
	<author>Joomla! Project</author>
	<creationDate>November 2005</creationDate>
	<copyright>(C) 2005 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_NEWSFEEDS_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="newsfeeds">newsfeeds.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_search_newsfeeds.ini</language>
		<language
tag="en-GB">en-GB.plg_search_newsfeeds.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="JFIELD_PLG_SEARCH_SEARCHLIMIT_LABEL"
					description="JFIELD_PLG_SEARCH_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="search_content"
					type="radio"
					label="JFIELD_PLG_SEARCH_ALL_LABEL"
					description="JFIELD_PLG_SEARCH_ALL_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="search_archived"
					type="radio"
					label="JFIELD_PLG_SEARCH_ARCHIVED_LABEL"
					description="JFIELD_PLG_SEARCH_ARCHIVED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JON</option>
					<option value="0">JOFF</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
search/tags/tags.php000064400000013342147357022240010427 0ustar00<?php

/**
 * @package     Joomla.Plugin
 * @subpackage  Search.tags
 *
 * @copyright   (C) 2014 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */
defined('_JEXEC') or die;

/**
 * Tags search plugin.
 *
 * @since  3.3
 */
class PlgSearchTags extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.3
	 */
	protected $autoloadLanguage = true;

	/**
	 * Determine areas searchable by this plugin.
	 *
	 * @return  array  An array of search areas.
	 *
	 * @since   3.3
	 */
	public function onContentSearchAreas()
	{
		static $areas = array(
			'tags' => 'PLG_SEARCH_TAGS_TAGS'
		);

		return $areas;
	}

	/**
	 * Search content (tags).
	 *
	 * The SQL must return the following fields that are used in a common
display
	 * routine: href, title, section, created, text, browsernav.
	 *
	 * @param   string  $text      Target search string.
	 * @param   string  $phrase    Matching option (possible values:
exact|any|all).  Default is "any".
	 * @param   string  $ordering  Ordering option (possible values:
newest|oldest|popular|alpha|category).  Default is "newest".
	 * @param   string  $areas     An array if the search is to be restricted
to areas or null to search all areas.
	 *
	 * @return  array  Search results.
	 *
	 * @since   3.3
	 */
	public function onContentSearch($text, $phrase = '', $ordering =
'', $areas = null)
	{
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true);
		$app   = JFactory::getApplication();
		$user  = JFactory::getUser();
		$lang  = JFactory::getLanguage();

		$section = JText::_('PLG_SEARCH_TAGS_TAGS');
		$limit   = $this->params->def('search_limit', 50);

		if (is_array($areas) && !array_intersect($areas,
array_keys($this->onContentSearchAreas())))
		{
			return array();
		}

		$text = trim($text);

		if ($text === '')
		{
			return array();
		}

		$text = $db->quote('%' . $db->escape($text, true) .
'%', false);

		switch ($ordering)
		{
			case 'alpha':
				$order = 'a.title ASC';
				break;

			case 'newest':
				$order = 'a.created_time DESC';
				break;

			case 'oldest':
				$order = 'a.created_time ASC';
				break;

			case 'popular':
			default:
				$order = 'a.title DESC';
		}

		$query->select('a.id, a.title, a.alias, a.note, a.published,
a.access'
			. ', a.checked_out, a.checked_out_time, a.created_user_id'
			. ', a.path, a.parent_id, a.level, a.lft, a.rgt'
			. ', a.language, a.created_time AS created, a.description');

		$case_when_item_alias  = ' CASE WHEN ';
		$case_when_item_alias .= $query->charLength('a.alias',
'!=', '0');
		$case_when_item_alias .= ' THEN ';
		$a_id                  = $query->castAsChar('a.id');
		$case_when_item_alias .= $query->concatenate(array($a_id,
'a.alias'), ':');
		$case_when_item_alias .= ' ELSE ';
		$case_when_item_alias .= $a_id . ' END as slug';
		$query->select($case_when_item_alias);

		$query->from('#__tags AS a');
		$query->where('a.alias <> ' .
$db->quote('root'));

		$query->where('(a.title LIKE ' . $text . ' OR a.alias
LIKE ' . $text . ')');

		$query->where($db->qn('a.published') . ' = 1');

		if (!$user->authorise('core.admin'))
		{
			$groups = implode(',', $user->getAuthorisedViewLevels());
			$query->where('a.access IN (' . $groups . ')');
		}

		if ($app->isClient('site') &&
JLanguageMultilang::isEnabled())
		{
			$tag = JFactory::getLanguage()->getTag();
			$query->where('a.language in (' . $db->quote($tag) .
',' . $db->quote('*') . ')');
		}

		$query->order($order);

		$db->setQuery($query, 0, $limit);

		try
		{
			$rows = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			$rows = array();
			JFactory::getApplication()->enqueueMessage(JText::_('JERROR_AN_ERROR_HAS_OCCURRED'),
'error');
		}

		if ($rows)
		{
			JLoader::register('TagsHelperRoute', JPATH_SITE .
'/components/com_tags/helpers/route.php');

			foreach ($rows as $key => $row)
			{
				$rows[$key]->href       =
TagsHelperRoute::getTagRoute($row->slug);
				$rows[$key]->text       = ($row->description !== '' ?
$row->description : $row->title);
				$rows[$key]->text      .= $row->note;
				$rows[$key]->section    = $section;
				$rows[$key]->created    = $row->created;
				$rows[$key]->browsernav = 0;
			}
		}

		if (!$this->params->get('show_tagged_items', 0))
		{
			return $rows;
		}
		else
		{
			$final_items = $rows;
			JModelLegacy::addIncludePath(JPATH_SITE .
'/components/com_tags/models');
			$tag_model = JModelLegacy::getInstance('Tag',
'TagsModel');
			$tag_model->getState();

			foreach ($rows as $key => $row)
			{
				$tag_model->setState('tag.id', $row->id);
				$tagged_items = $tag_model->getItems();

				if ($tagged_items)
				{
					foreach ($tagged_items as $k => $item)
					{
						// For 3rd party extensions we need to load the component strings
from its sys.ini file
						$parts = explode('.', $item->type_alias);
						$comp = array_shift($parts);
						$lang->load($comp, JPATH_SITE, null, false, true)
						|| $lang->load($comp, JPATH_SITE . '/components/' .
$comp, null, false, true);

						// Making up the type string
						$type = implode('_', $parts);
						$type = $comp . '_CONTENT_TYPE_' . $type;

						$new_item        = new stdClass;
						$new_item->href  = $item->link;
						$new_item->title = $item->core_title;
						$new_item->text  = $item->core_body;

						if ($lang->hasKey($type))
						{
							$new_item->section =
JText::sprintf('PLG_SEARCH_TAGS_ITEM_TAGGED_WITH',
JText::_($type), $row->title);
						}
						else
						{
							$new_item->section =
JText::sprintf('PLG_SEARCH_TAGS_ITEM_TAGGED_WITH',
$item->content_type_title, $row->title);
						}

						$new_item->created    = $item->displayDate;
						$new_item->browsernav = 0;
						$final_items[]        = $new_item;
					}
				}
			}

			return $final_items;
		}
	}
}
search/tags/tags.xml000064400000002630147357022240010436 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="search" method="upgrade">
	<name>plg_search_tags</name>
	<author>Joomla! Project</author>
	<creationDate>March 2014</creationDate>
	<copyright>(C) 2014 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEARCH_TAGS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="tags">tags.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_search_tags.ini</language>
		<language
tag="en-GB">en-GB.plg_search_tags.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="search_limit"
					type="number"
					label="JFIELD_PLG_SEARCH_SEARCHLIMIT_LABEL"
					description="JFIELD_PLG_SEARCH_SEARCHLIMIT_DESC"
					default="50"
					filter="integer"
					size="5"
				/>

				<field
					name="show_tagged_items"
					type="radio"
					label="PLG_SEARCH_TAGS_FIELD_SHOW_TAGGED_ITEMS_LABEL"
					description="PLG_SEARCH_TAGS_FIELD_SHOW_TAGGED_ITEMS_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
system/actionlogs/actionlogs.php000064400000027672147357022240013131
0ustar00<?php
/**
 * @package     Joomla.Plugins
 * @subpackage  System.actionlogs
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Cache\Cache;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\User;

/**
 * Joomla! Users Actions Logging Plugin.
 *
 * @since  3.9.0
 */
class PlgSystemActionLogs extends JPlugin
{
	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.9.0
	 */
	protected $db;

	/**
	 * Load plugin language file automatically so that it can be used inside
component
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of
configuration settings.
	 *
	 * @since   3.9.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		// Import actionlog plugin group so that these plugins will be triggered
for events
		PluginHelper::importPlugin('actionlog');
	}

	/**
	 * Adds additional fields to the user editing form for logs e-mail
notifications
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareForm($form, $data)
	{
		if (!$form instanceof Form)
		{
			$this->subject->setError('JERROR_NOT_A_FORM');

			return false;
		}

		$formName = $form->getName();

		$allowedFormNames = array(
			'com_users.profile',
			'com_admin.profile',
			'com_users.user',
		);

		if (!in_array($formName, $allowedFormNames))
		{
			return true;
		}

		/**
		 * We only allow users who has Super User permission change this setting
for himself or for other users
		 * who has same Super User permission
		 */

		$user = Factory::getUser();

		if (!$user->authorise('core.admin'))
		{
			return true;
		}

		// If we are on the save command, no data is passed to $data variable, we
need to get it directly from request
		$jformData = $this->app->input->get('jform', array(),
'array');

		if ($jformData && !$data)
		{
			$data = $jformData;
		}

		if (is_array($data))
		{
			$data = (object) $data;
		}

		if (empty($data->id) ||
!User::getInstance($data->id)->authorise('core.admin'))
		{
			return true;
		}

		Form::addFormPath(__DIR__ . '/forms');

		if ((!PluginHelper::isEnabled('actionlog', 'joomla'))
&&
(Factory::getApplication()->isClient('administrator')))
		{
			$form->loadFile('information', false);

			return true;
		}

		if (!PluginHelper::isEnabled('actionlog', 'joomla'))
		{
			return true;
		}

		$form->loadFile('actionlogs', false);
	}

	/**
	 * Runs on content preparation
	 *
	 * @param   string  $context  The context for the data
	 * @param   object  $data     An object containing the data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareData($context, $data)
	{
		if (!in_array($context, array('com_users.profile',
'com_admin.profile', 'com_users.user')))
		{
			return true;
		}

		if (is_array($data))
		{
			$data = (object) $data;
		}

		if
(!User::getInstance($data->id)->authorise('core.admin'))
		{
			return true;
		}

		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('notify',
'extensions')))
			->from($this->db->quoteName('#__action_logs_users'))
			->where($this->db->quoteName('user_id') . ' =
' . (int) $data->id);

		try
		{
			$values = $this->db->setQuery($query)->loadObject();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		if (!$values)
		{
			return true;
		}

		$data->actionlogs                       = new StdClass;
		$data->actionlogs->actionlogsNotify     = $values->notify;
		$data->actionlogs->actionlogsExtensions = $values->extensions;

		if (!HTMLHelper::isRegistered('users.actionlogsNotify'))
		{
			HTMLHelper::register('users.actionlogsNotify',
array(__CLASS__, 'renderActionlogsNotify'));
		}

		if (!HTMLHelper::isRegistered('users.actionlogsExtensions'))
		{
			HTMLHelper::register('users.actionlogsExtensions',
array(__CLASS__, 'renderActionlogsExtensions'));
		}

		return true;
	}

	/**
	 * Runs after the HTTP response has been sent to the client and delete log
records older than certain days
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onAfterRespond()
	{
		$daysToDeleteAfter = (int)
$this->params->get('logDeletePeriod', 0);

		if ($daysToDeleteAfter <= 0)
		{
			return;
		}

		// The delete frequency will be once per day
		$deleteFrequency = 3600 * 24;

		// Do we need to run? Compare the last run timestamp stored in the
plugin's options with the current
		// timestamp. If the difference is greater than the cache timeout we
shall not execute again.
		$now  = time();
		$last = (int) $this->params->get('lastrun', 0);

		if (abs($now - $last) < $deleteFrequency)
		{
			return;
		}

		// Update last run status
		$this->params->set('lastrun', $now);

		$db    = $this->db;
		$query = $db->getQuery(true)
			->update($db->qn('#__extensions'))
			->set($db->qn('params') . ' = ' .
$db->q($this->params->toString('JSON')))
			->where($db->qn('type') . ' = ' .
$db->q('plugin'))
			->where($db->qn('folder') . ' = ' .
$db->q('system'))
			->where($db->qn('element') . ' = ' .
$db->q('actionlogs'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race
condition
			$db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue
execution
			return;
		}

		try
		{
			// Update the plugin parameters
			$result = $db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		// Abort on failure
		if (!$result)
		{
			return;
		}

		$daysToDeleteAfter = (int)
$this->params->get('logDeletePeriod', 0);
		$now = $db->quote(Factory::getDate()->toSql());

		if ($daysToDeleteAfter > 0)
		{
			$conditions = array($db->quoteName('log_date') . '
< ' . $query->dateAdd($now, -1 * $daysToDeleteAfter, '
DAY'));

			$query->clear()
				->delete($db->quoteName('#__action_logs'))->where($conditions);
			$db->setQuery($query);

			try
			{
				$db->execute();
			}
			catch (RuntimeException $e)
			{
				// Ignore it
				return;
			}
		}
	}

	/**
	 * Utility method to act on a user after it has been saved.
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isNew    True if a new user is stored.
	 * @param   boolean  $success  True if user was successfully stored in the
database.
	 * @param   string   $msg      Message.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSave($user, $isNew, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		// Clear access rights in case user groups were changed.
		$userObject = new User($user['id']);
		$userObject->clearAccessRights();
		$authorised = $userObject->authorise('core.admin');

		$query = $this->db->getQuery(true)
			->select('COUNT(*)')
			->from($this->db->quoteName('#__action_logs_users'))
			->where($this->db->quoteName('user_id') . ' =
' . (int) $user['id']);

		try
		{
			$exists = (bool) $this->db->setQuery($query)->loadResult();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		// If preferences don't exist, insert.
		if (!$exists && $authorised &&
isset($user['actionlogs']))
		{
			$values  = array((int) $user['id'], (int)
$user['actionlogs']['actionlogsNotify']);
			$columns = array('user_id', 'notify');

			if
(isset($user['actionlogs']['actionlogsExtensions']))
			{
				$values[]  =
$this->db->quote(json_encode($user['actionlogs']['actionlogsExtensions']));
				$columns[] = 'extensions';
			}

			$query = $this->db->getQuery(true)
				->insert($this->db->quoteName('#__action_logs_users'))
				->columns($this->db->quoteName($columns))
				->values(implode(',', $values));
		}
		elseif ($exists && $authorised &&
isset($user['actionlogs']))
		{
			// Update preferences.
			$values = array($this->db->quoteName('notify') . '
= ' . (int)
$user['actionlogs']['actionlogsNotify']);

			if
(isset($user['actionlogs']['actionlogsExtensions']))
			{
				$values[] = $this->db->quoteName('extensions') . '
= ' .
$this->db->quote(json_encode($user['actionlogs']['actionlogsExtensions']));
			}

			$query = $this->db->getQuery(true)
				->update($this->db->quoteName('#__action_logs_users'))
				->set($values)
				->where($this->db->quoteName('user_id') . ' =
' . (int) $user['id']);
		}
		elseif ($exists && !$authorised)
		{
			// Remove preferences if user is not authorised.
			$query = $this->db->getQuery(true)
				->delete($this->db->quoteName('#__action_logs_users'))
				->where($this->db->quoteName('user_id') . ' =
' . (int) $user['id']);
		}

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Removes user preferences
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the
database
	 * @param   string   $msg      Message
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		$query = $this->db->getQuery(true)
			->delete($this->db->quoteName('#__action_logs_users'))
			->where($this->db->quoteName('user_id') . ' =
' . (int) $user['id']);

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
	{
		$conf = Factory::getConfig();

		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $clientId)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $clientId ? JPATH_ADMINISTRATOR .
'/cache' :
							$conf->get('cache_path', JPATH_SITE .
'/cache')
					);

					$cache = Cache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}

	/**
	 * Method to render a value.
	 *
	 * @param   integer|string  $value  The value (0 or 1).
	 *
	 * @return  string  The rendered value.
	 *
	 * @since   3.9.16
	 */
	public static function renderActionlogsNotify($value)
	{
		return Text::_($value ? 'JYES' : 'JNO');
	}

	/**
	 * Method to render a list of extensions.
	 *
	 * @param   array|string  $extensions  Array of extensions or an empty
string if none selected.
	 *
	 * @return  string  The rendered value.
	 *
	 * @since   3.9.16
	 */
	public static function renderActionlogsExtensions($extensions)
	{
		// No extensions selected.
		if (!$extensions)
		{
			return Text::_('JNONE');
		}

		// Load the helper.
		JLoader::register('ActionlogsHelper', JPATH_ADMINISTRATOR .
'/components/com_actionlogs/helpers/actionlogs.php');

		foreach ($extensions as &$extension)
		{
			// Load extension language files and translate extension name.
			ActionlogsHelper::loadTranslationFiles($extension);
			$extension = Text::_($extension);
		}

		return implode(', ', $extensions);
	}
}
system/actionlogs/actionlogs.xml000064400000002363147357022240013130
0ustar00<?xml version="1.0" encoding="UTF-8"?>
<extension version="3.9" type="plugin"
group="system" method="upgrade">
	<name>PLG_SYSTEM_ACTIONLOGS</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_SYSTEM_ACTIONLOGS_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="actionlogs">actionlogs.php</filename>
		<folder>forms</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_actionlogs.ini</language>
		<language
tag="en-GB">en-GB.plg_system_actionlogs.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="logDeletePeriod"
					type="number"
					label="PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD"
					description="PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD_DESC"
					default="0"
					min="0"
					filter="int"
					validate="number"
				/>
				<field
					name="lastrun"
					type="hidden"
					default="0"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
system/actionlogs/forms/actionlogs.xml000064400000001537147357022250014261
0ustar00<?xml version="1.0" encoding="UTF-8"?>
<form>
	<fieldset name="actionlogs"
label="PLG_SYSTEM_ACTIONLOGS_OPTIONS"
addfieldpath="/administrator/components/com_actionlogs/models/fields">
		<fields name="actionlogs">
			<field
				name="actionlogsNotify"
				type="radio"
				label="PLG_SYSTEM_ACTIONLOGS_NOTIFICATIONS"
				description="PLG_SYSTEM_ACTIONLOGS_NOTIFICATIONS_DESC"
				class="btn-group btn-group-yesno"
				default="0"
				filter="integer"
				required="true"
				>
				<option value="1">JYES</option>
				<option value="0">JNO</option>
			</field>
			<field
				name="actionlogsExtensions"
				type="logtype"
				label="PLG_SYSTEM_ACTIONLOGS_EXTENSIONS_NOTIFICATIONS"
				description="PLG_SYSTEM_ACTIONLOGS_EXTENSIONS_NOTIFICATIONS_DESC"
				multiple="true"
				validate="options"
				showon="actionlogsNotify:1"
			/>
		</fields>
	</fieldset>
</form>
system/actionlogs/forms/information.xml000064400000000617147357022250014442
0ustar00<?xml version="1.0" encoding="UTF-8"?>
<form>
	<fields name="params">
		<fieldset name="information"
label="PLG_SYSTEM_ACTIONLOGS_OPTIONS"
addfieldpath="/administrator/components/com_actionlogs/models/fields">
			<field
				name="Information"
				type="plugininfo"
				label="PLG_SYSTEM_ACTIONLOGS_INFO_LABEL"
				description="PLG_SYSTEM_ACTIONLOGS_INFO_DESC"
			/>
		</fieldset>
	</fields>
</form>
system/cache/cache.php000064400000013143147357022250010720 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.cache
 *
 * @copyright   (C) 2007 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! Page Cache Plugin.
 *
 * @since  1.5
 */
class PlgSystemCache extends JPlugin
{
	/**
	 * Cache instance.
	 *
	 * @var    JCache
	 * @since  1.5
	 */
	public $_cache;

	/**
	 * Cache key
	 *
	 * @var    string
	 * @since  3.0
	 */
	public $_cache_key;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.8.0
	 */
	protected $app;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of
configuration settings.
	 *
	 * @since   1.5
	 */
	public function __construct(& $subject, $config)
	{
		parent::__construct($subject, $config);

		// Get the application if not done by JPlugin.
		if (!isset($this->app))
		{
			$this->app = JFactory::getApplication();
		}

		// Set the cache options.
		$options = array(
			'defaultgroup' => 'page',
			'browsercache' =>
$this->params->get('browsercache', 0),
			'caching'      => false,
		);

		// Instantiate cache with previous options and create the cache key
identifier.
		$this->_cache     = JCache::getInstance('page', $options);
		$this->_cache_key = JUri::getInstance()->toString();
	}

	/**
	 * Get a cache key for the current page based on the url and possible
other factors.
	 *
	 * @return  string
	 *
	 * @since   3.7
	 */
	protected function getCacheKey()
	{
		static $key;

		if (!$key)
		{
			JPluginHelper::importPlugin('pagecache');

			$parts =
JEventDispatcher::getInstance()->trigger('onPageCacheGetKey');
			$parts[] = JUri::getInstance()->toString();

			$key = md5(serialize($parts));
		}

		return $key;
	}

	/**
	 * After Initialise Event.
	 * Checks if URL exists in cache, if so dumps it directly and closes.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onAfterInitialise()
	{
		if ($this->app->isClient('administrator') ||
$this->app->get('offline', '0') ||
$this->app->getMessageQueue())
		{
			return;
		}

		// If any pagecache plugins return false for onPageCacheSetCaching, do
not use the cache.
		JPluginHelper::importPlugin('pagecache');

		$results =
JEventDispatcher::getInstance()->trigger('onPageCacheSetCaching');
		$caching = !in_array(false, $results, true);

		if ($caching && JFactory::getUser()->guest &&
$this->app->input->getMethod() === 'GET')
		{
			$this->_cache->setCaching(true);
		}

		$data = $this->_cache->get($this->getCacheKey());

		// If page exist in cache, show cached page.
		if ($data !== false)
		{
			// Set HTML page from cache.
			$this->app->setBody($data);

			// Dumps HTML page.
			echo $this->app->toString((bool)
$this->app->get('gzip'));

			// Mark afterCache in debug and run debug onAfterRespond events.
			// e.g., show Joomla Debug Console if debug is active.
			if (JDEBUG)
			{
				JProfiler::getInstance('Application')->mark('afterCache');
				JEventDispatcher::getInstance()->trigger('onAfterRespond');
			}

			// Closes the application.
			$this->app->close();
		}
	}

	/**
	 * After Render Event.
	 * Verify if current page is not excluded from cache.
	 *
	 * @return   void
	 *
	 * @since   3.9.12
	 */
	public function onAfterRender()
	{
		if ($this->_cache->getCaching() === false)
		{
			return;
		}

		// We need to check if user is guest again here, because auto-login
plugins have not been fired before the first aid check.
		// Page is excluded if excluded in plugin settings.
		if (!JFactory::getUser()->guest || $this->app->getMessageQueue()
|| $this->isExcluded() === true)
		{
			$this->_cache->setCaching(false);

			return;
		}

		// Disable compression before caching the page.
		$this->app->set('gzip', false);
	}

	/**
	 * After Respond Event.
	 * Stores page in cache.
	 *
	 * @return   void
	 *
	 * @since   1.5
	 */
	public function onAfterRespond()
	{
		if ($this->_cache->getCaching() === false)
		{
			return;
		}

		// Saves current page in cache.
		$this->_cache->store($this->app->getBody(),
$this->getCacheKey());
	}

	/**
	 * Check if the page is excluded from the cache or not.
	 *
	 * @return   boolean  True if the page is excluded else false
	 *
	 * @since    3.5
	 */
	protected function isExcluded()
	{
		// Check if menu items have been excluded.
		if ($exclusions =
$this->params->get('exclude_menu_items', array()))
		{
			// Get the current menu item.
			$active = $this->app->getMenu()->getActive();

			if ($active && $active->id && in_array((int)
$active->id, (array) $exclusions))
			{
				return true;
			}
		}

		// Check if regular expressions are being used.
		if ($exclusions = $this->params->get('exclude',
''))
		{
			// Normalize line endings.
			$exclusions = str_replace(array("\r\n", "\r"),
"\n", $exclusions);

			// Split them.
			$exclusions = explode("\n", $exclusions);

			// Gets internal URI.
			$internal_uri	= '/index.php?' .
JUri::getInstance()->buildQuery($this->app->getRouter()->getVars());

			// Loop through each pattern.
			if ($exclusions)
			{
				foreach ($exclusions as $exclusion)
				{
					// Make sure the exclusion has some content
					if ($exclusion !== '')
					{
						// Test both external and internal URI
						if (preg_match('#' . $exclusion . '#i',
$this->_cache_key . ' ' . $internal_uri, $match))
						{
							return true;
						}
					}
				}
			}
		}

		// If any pagecache plugins return true for onPageCacheIsExcluded,
exclude.
		JPluginHelper::importPlugin('pagecache');

		$results =
JEventDispatcher::getInstance()->trigger('onPageCacheIsExcluded');

		return in_array(true, $results, true);
	}
}
system/cache/cache.xml000064400000003215147357022250010730 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_cache</name>
	<author>Joomla! Project</author>
	<creationDate>February 2007</creationDate>
	<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CACHE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="cache">cache.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_cache.ini</language>
		<language
tag="en-GB">en-GB.plg_system_cache.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="browsercache"
					type="radio"
					label="PLG_CACHE_FIELD_BROWSERCACHE_LABEL"
					description="PLG_CACHE_FIELD_BROWSERCACHE_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="exclude_menu_items"
					type="menuitem"
					label="PLG_CACHE_FIELD_EXCLUDE_MENU_ITEMS_LABEL"
					description="PLG_CACHE_FIELD_EXCLUDE_MENU_ITEMS_DESC"
					multiple="multiple"
					filter="int_array"
				/>

			</fieldset>
			<fieldset name="advanced">
				<field
					name="exclude"
					type="textarea"
					label="PLG_CACHE_FIELD_EXCLUDE_LABEL"
					description="PLG_CACHE_FIELD_EXCLUDE_DESC"
					class="input-xxlarge"
					rows="15"
					filter="raw"
				/>

			</fieldset>
		</fields>
	</config>
</extension>
system/debug/debug.php000064400000141542147357022250010773 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.Debug
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Utilities\ArrayHelper;

/**
 * Joomla! Debug plugin.
 *
 * @since  1.5
 */
class PlgSystemDebug extends JPlugin
{
	/**
	 * xdebug.file_link_format from the php.ini.
	 *
	 * @var    string
	 * @since  1.7
	 */
	protected $linkFormat = '';

	/**
	 * True if debug lang is on.
	 *
	 * @var    boolean
	 * @since  3.0
	 */
	private $debugLang = false;

	/**
	 * Holds log entries handled by the plugin.
	 *
	 * @var    array
	 * @since  3.1
	 */
	private $logEntries = array();

	/**
	 * Holds SHOW PROFILES of queries.
	 *
	 * @var    array
	 * @since  3.1.2
	 */
	private $sqlShowProfiles = array();

	/**
	 * Holds all SHOW PROFILE FOR QUERY n, indexed by n-1.
	 *
	 * @var    array
	 * @since  3.1.2
	 */
	private $sqlShowProfileEach = array();

	/**
	 * Holds all EXPLAIN EXTENDED for all queries.
	 *
	 * @var    array
	 * @since  3.1.2
	 */
	private $explains = array();

	/**
	 * Holds total amount of executed queries.
	 *
	 * @var    int
	 * @since  3.2
	 */
	private $totalQueries = 0;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.3
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.8.0
	 */
	protected $db;

	/**
	 * Container for callback functions to be triggered when rendering the
console.
	 *
	 * @var    callable[]
	 * @since  3.7.0
	 */
	private static $displayCallbacks = array();

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe.
	 * @param   array   $config    An optional associative array of
configuration settings.
	 *
	 * @since   1.5
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		// Log the deprecated API.
		if ($this->params->get('log-deprecated', 0))
		{
			JLog::addLogger(array('text_file' =>
'deprecated.php'), JLog::ALL, array('deprecated'));
		}

		// Log everything (except deprecated APIs, these are logged separately
with the option above).
		if ($this->params->get('log-everything', 0))
		{
			JLog::addLogger(array('text_file' =>
'everything.php'), JLog::ALL, array('deprecated',
'databasequery'), true);
		}

		// Get the application if not done by JPlugin. This may happen during
upgrades from Joomla 2.5.
		if (!$this->app)
		{
			$this->app = JFactory::getApplication();
		}

		// Get the db if not done by JPlugin. This may happen during upgrades
from Joomla 2.5.
		if (!$this->db)
		{
			$this->db = JFactory::getDbo();
		}

		$this->debugLang = $this->app->get('debug_lang');

		// Skip the plugin if debug is off
		if ($this->debugLang == '0' &&
$this->app->get('debug') == '0')
		{
			return;
		}

		// Only if debugging or language debug is enabled.
		if (JDEBUG || $this->debugLang)
		{
			JFactory::getConfig()->set('gzip', 0);
			ob_start();
			ob_implicit_flush(false);
		}

		$this->linkFormat = ini_get('xdebug.file_link_format');

		if ($this->params->get('logs', 1))
		{
			$priority = 0;

			foreach ($this->params->get('log_priorities', array())
as $p)
			{
				$const = 'JLog::' . strtoupper($p);

				if (!defined($const))
				{
					continue;
				}

				$priority |= constant($const);
			}

			// Split into an array at any character other than alphabet, numbers, _,
., or -
			$categories = preg_split('/[^\w.-]+/',
$this->params->get('log_categories', ''), -1,
PREG_SPLIT_NO_EMPTY);
			$mode       = $this->params->get('log_category_mode',
0);

			JLog::addLogger(array('logger' => 'callback',
'callback' => array($this, 'logger')), $priority,
$categories, $mode);
		}

		// Prepare disconnect handler for SQL profiling.
		$db = $this->db;
		$db->addDisconnectHandler(array($this,
'mysqlDisconnectHandler'));

		// Log deprecated class aliases
		foreach (JLoader::getDeprecatedAliases() as $deprecation)
		{
			JLog::add(
				sprintf(
					'%1$s has been aliased to %2$s and the former class name is
deprecated. The alias will be removed in %3$s.',
					$deprecation['old'],
					$deprecation['new'],
					$deprecation['version']
				),
				JLog::WARNING,
				'deprecated'
			);
		}
	}

	/**
	 * Add the CSS for debug.
	 * We can't do this in the constructor because stuff breaks.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onAfterDispatch()
	{
		// Only if debugging or language debug is enabled.
		if ((JDEBUG || $this->debugLang) &&
$this->isAuthorisedDisplayDebug())
		{
			JHtml::_('stylesheet', 'cms/debug.css',
array('version' => 'auto', 'relative'
=> true));
		}

		// Disable asset media version if needed.
		if (JDEBUG && (int)
$this->params->get('refresh_assets', 1) === 0)
		{
			$this->app->getDocument()->setMediaVersion(null);
		}

		// Only if debugging is enabled for SQL query popovers.
		if (JDEBUG && $this->isAuthorisedDisplayDebug())
		{
			JHtml::_('bootstrap.tooltip');
			JHtml::_('bootstrap.popover', '.hasPopover',
array('placement' => 'top'));
		}
	}

	/**
	 * Show the debug info.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onAfterRespond()
	{
		// Do not render if debugging or language debug is not enabled.
		if (!JDEBUG && !$this->debugLang)
		{
			return;
		}

		// User has to be authorised to see the debug information.
		if (!$this->isAuthorisedDisplayDebug())
		{
			return;
		}

		// Only render for HTML output.
		if (JFactory::getDocument()->getType() !== 'html')
		{
			return;
		}

		// Capture output.
		$contents = ob_get_contents();

		if ($contents)
		{
			ob_end_clean();
		}

		// No debug for Safari and Chrome redirection.
		if (strpos($contents, '<html><head><meta
http-equiv="refresh" content="0;') === 0
			&&
strpos(strtolower(isset($_SERVER['HTTP_USER_AGENT']) ?
$_SERVER['HTTP_USER_AGENT'] : ''), 'webkit')
!== false)
		{
			echo $contents;

			return;
		}

		// Load language.
		$this->loadLanguage();

		$html = array();

		// Some "mousewheel protecting" JS.
		$html[] = "<script>function toggleContainer(name)
		{
			var e = document.getElementById(name);// MooTools might not be available
;)
			e.style.display = e.style.display === 'none' ?
'block' : 'none';
		}</script>";

		$html[] = '<div id="system-debug"
class="profiler">';

		$html[] = '<h2>' . JText::_('PLG_DEBUG_TITLE')
. '</h2>';

		if (JDEBUG)
		{
			if (JError::getErrors())
			{
				$html[] = $this->display('errors');
			}

			if ($this->params->get('session', 1))
			{
				$html[] = $this->display('session');
			}

			if ($this->params->get('profile', 1))
			{
				$html[] = $this->display('profile_information');
			}

			if ($this->params->get('memory', 1))
			{
				$html[] = $this->display('memory_usage');
			}

			if ($this->params->get('queries', 1))
			{
				$html[] = $this->display('queries');
			}

			if (!empty($this->logEntries) &&
$this->params->get('logs', 1))
			{
				$html[] = $this->display('logs');
			}
		}

		if ($this->debugLang)
		{
			if ($this->params->get('language_errorfiles', 1))
			{
				$languageErrors = JFactory::getLanguage()->getErrorFiles();
				$html[]         =
$this->display('language_files_in_error', $languageErrors);
			}

			if ($this->params->get('language_files', 1))
			{
				$html[] = $this->display('language_files_loaded');
			}

			if ($this->params->get('language_strings', 1))
			{
				$html[] = $this->display('untranslated_strings');
			}
		}

		foreach (self::$displayCallbacks as $name => $callable)
		{
			$html[] = $this->displayCallback($name, $callable);
		}

		$html[] = '</div>';

		echo str_replace('</body>', implode('', $html)
. '</body>', $contents);
	}

	/**
	 * Add a display callback to be rendered with the debug console.
	 *
	 * @param   string    $name      The name of the callable, this is used to
generate the section title.
	 * @param   callable  $callable  The callback function to be added.
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 * @throws  InvalidArgumentException
	 */
	public static function addDisplayCallback($name, $callable)
	{
		// TODO - When PHP 5.4 is the minimum the parameter should be typehinted
"callable" and this check removed
		if (!is_callable($callable))
		{
			throw new InvalidArgumentException('A valid callback function must
be given.');
		}

		self::$displayCallbacks[$name] = $callable;

		return true;
	}

	/**
	 * Remove a registered display callback
	 *
	 * @param   string  $name  The name of the callable.
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public static function removeDisplayCallback($name)
	{
		unset(self::$displayCallbacks[$name]);

		return true;
	}

	/**
	 * Method to check if the current user is allowed to see the debug
information or not.
	 *
	 * @return  boolean  True if access is allowed.
	 *
	 * @since   3.0
	 */
	private function isAuthorisedDisplayDebug()
	{
		static $result = null;

		if ($result !== null)
		{
			return $result;
		}

		// If the user is not allowed to view the output then end here.
		$filterGroups = (array)
$this->params->get('filter_groups', array());

		if (!empty($filterGroups))
		{
			$userGroups = JFactory::getUser()->get('groups');

			if (!array_intersect($filterGroups, $userGroups))
			{
				$result = false;

				return false;
			}
		}

		$result = true;

		return true;
	}

	/**
	 * General display method.
	 *
	 * @param   string  $item    The item to display.
	 * @param   array   $errors  Errors occurred during execution.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function display($item, array $errors = array())
	{
		$title = JText::_('PLG_DEBUG_' . strtoupper($item));

		$status = '';

		if (count($errors))
		{
			$status = ' dbg-error';
		}

		$fncName = 'display' . ucfirst(str_replace('_',
'', $item));

		if (!method_exists($this, $fncName))
		{
			return __METHOD__ . ' -- Unknown method: ' . $fncName .
'<br />';
		}

		$html = array();

		$js = "toggleContainer('dbg_container_" . $item .
"');";

		$class = 'dbg-header' . $status;

		$html[] = '<div class="' . $class . '"
onclick="' . $js . '"><a
href="javascript:void(0);"><h3>' . $title .
'</h3></a></div>';

		// @todo set with js.. ?
		$style = ' style="display: none;"';

		$html[] = '<div ' . $style . '
class="dbg-container" id="dbg_container_' . $item .
'">';
		$html[] = $this->$fncName();
		$html[] = '</div>';

		return implode('', $html);
	}

	/**
	 * Display method for callback functions.
	 *
	 * @param   string    $name      The name of the callable.
	 * @param   callable  $callable  The callable function.
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	protected function displayCallback($name, $callable)
	{
		$title = JText::_('PLG_DEBUG_' . strtoupper($name));

		$html = array();

		$js = "toggleContainer('dbg_container_" . $name .
"');";

		$class = 'dbg-header';

		$html[] = '<div class="' . $class . '"
onclick="' . $js . '"><a
href="javascript:void(0);"><h3>' . $title .
'</h3></a></div>';

		// @todo set with js.. ?
		$style = ' style="display: none;"';

		$html[] = '<div ' . $style . '
class="dbg-container" id="dbg_container_' . $name .
'">';
		$html[] = call_user_func($callable);
		$html[] = '</div>';

		return implode('', $html);
	}

	/**
	 * Display session information.
	 *
	 * Called recursively.
	 *
	 * @param   string   $key      A session key.
	 * @param   mixed    $session  The session array, initially null.
	 * @param   integer  $id       Used to identify the DIV for the JavaScript
toggling code.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displaySession($key = '', $session = null,
$id = 0)
	{
		if (!$session)
		{
			$session = JFactory::getSession()->getData();
		}

		$html = array();
		static $id;

		if (!is_array($session))
		{
			$html[] = $key . '<pre>' .
$this->prettyPrintJSON($session) . '</pre>' . PHP_EOL;
		}
		else
		{
			foreach ($session as $sKey => $entries)
			{
				$display = true;

				if (is_array($entries) && $entries)
				{
					$display = false;
				}

				if (is_object($entries))
				{
					$o = ArrayHelper::fromObject($entries);

					if ($o)
					{
						$entries = $o;
						$display = false;
					}
				}

				if (!$display)
				{
					$js = "toggleContainer('dbg_container_session" . $id .
'_' . $sKey . "');";

					$html[] = '<div class="dbg-header"
onclick="' . $js . '"><a
href="javascript:void(0);"><h3>' . $sKey .
'</h3></a></div>';

					// @todo set with js.. ?
					$style = ' style="display: none;"';

					$html[] = '<div ' . $style . '
class="dbg-container" id="dbg_container_session' . $id
. '_' . $sKey . '">';
					$id++;

					// Recurse...
					$this->displaySession($sKey, $entries, $id);

					$html[] = '</div>';

					continue;
				}

				if (is_array($entries))
				{
					$entries = implode($entries);
				}

				if (is_string($entries))
				{
					$html[] = $sKey . '<pre>' .
$this->prettyPrintJSON($entries) . '</pre>' . PHP_EOL;
				}
			}
		}

		return implode('', $html);
	}

	/**
	 * Display errors.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayErrors()
	{
		$html = array();

		$html[] = '<ol>';

		while ($error = JError::getError(true))
		{
			$col = (E_WARNING == $error->get('level')) ?
'red' : 'orange';

			$html[] = '<li>';
			$html[] = '<b style="color: ' . $col .
'">' . $error->getMessage() . '</b><br
/>';

			$info = $error->get('info');

			if ($info)
			{
				$html[] = '<pre>' . print_r($info, true) .
'</pre><br />';
			}

			$html[] = $this->renderBacktrace($error);
			$html[] = '</li>';
		}

		$html[] = '</ol>';

		return implode('', $html);
	}

	/**
	 * Display profile information.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayProfileInformation()
	{
		$html = array();

		$htmlMarks = array();

		$totalTime = 0;
		$totalMem  = 0;
		$marks     = array();
		$bars      = array();
		$barsMem   = array();

		foreach (JProfiler::getInstance('Application')->getMarks()
as $mark)
		{
			$totalTime += $mark->time;
			$totalMem  += (float) $mark->memory;
			$htmlMark  = sprintf(
				JText::_('PLG_DEBUG_TIME') . ': <span
class="label label-time">%.2f&nbsp;ms</span> /
<span class="label
label-default">%.2f&nbsp;ms</span>'
				. ' ' . JText::_('PLG_DEBUG_MEMORY') . ':
<span class="label label-memory">%0.3f MB</span> /
<span class="label label-default">%0.2f
MB</span>'
				. ' %s: %s',
				$mark->time,
				$mark->totalTime,
				$mark->memory,
				$mark->totalMemory,
				$mark->prefix,
				$mark->label
			);

			$marks[] = (object) array(
				'time'   => $mark->time,
				'memory' => $mark->memory,
				'html'   => $htmlMark,
				'tip'    => $mark->label,
			);
		}

		$avgTime = $totalTime / max(count($marks), 1);
		$avgMem  = $totalMem / max(count($marks), 1);

		foreach ($marks as $mark)
		{
			if ($mark->time > $avgTime * 1.5)
			{
				$barClass   = 'bar-danger';
				$labelClass = 'label-important label-danger';
			}
			elseif ($mark->time < $avgTime / 1.5)
			{
				$barClass   = 'bar-success';
				$labelClass = 'label-success';
			}
			else
			{
				$barClass   = 'bar-warning';
				$labelClass = 'label-warning';
			}

			if ($mark->memory > $avgMem * 1.5)
			{
				$barClassMem   = 'bar-danger';
				$labelClassMem = 'label-important label-danger';
			}
			elseif ($mark->memory < $avgMem / 1.5)
			{
				$barClassMem   = 'bar-success';
				$labelClassMem = 'label-success';
			}
			else
			{
				$barClassMem   = 'bar-warning';
				$labelClassMem = 'label-warning';
			}

			$barClass    .= " progress-$barClass";
			$barClassMem .= " progress-$barClassMem";

			$bars[] = (object) array(
				'width' => round($mark->time / ($totalTime / 100), 4),
				'class' => $barClass,
				'tip'   => $mark->tip . ' ' .
round($mark->time, 2) . ' ms',
			);

			$barsMem[] = (object) array(
				'width' => round((float) $mark->memory / ($totalMem /
100), 4),
				'class' => $barClassMem,
				'tip'   => $mark->tip . ' ' .
round($mark->memory, 3) . '  MB',
			);

			$htmlMarks[] = '<div>' .
str_replace('label-time', $labelClass,
str_replace('label-memory', $labelClassMem, $mark->html)) .
'</div>';
		}

		$html[] = '<h4>' . JText::_('PLG_DEBUG_TIME') .
'</h4>';
		$html[] = $this->renderBars($bars, 'profile');
		$html[] = '<h4>' . JText::_('PLG_DEBUG_MEMORY')
. '</h4>';
		$html[] = $this->renderBars($barsMem, 'profile');

		$html[] = '<div class="dbg-profile-list">' .
implode('', $htmlMarks) . '</div>';

		$db = $this->db;

		//  fix  for support custom shutdown function via
register_shutdown_function().
		$db->disconnect();

		$log = $db->getLog();

		if ($log)
		{
			$timings = $db->getTimings();

			if ($timings)
			{
				$totalQueryTime = 0.0;
				$lastStart      = null;

				foreach ($timings as $k => $v)
				{
					if (!($k % 2))
					{
						$lastStart = $v;
					}
					else
					{
						$totalQueryTime += $v - $lastStart;
					}
				}

				$totalQueryTime *= 1000;

				if ($totalQueryTime > ($totalTime * 0.25))
				{
					$labelClass = 'label-important';
				}
				elseif ($totalQueryTime < ($totalTime * 0.15))
				{
					$labelClass = 'label-success';
				}
				else
				{
					$labelClass = 'label-warning';
				}

				$html[] = '<br /><div>' . JText::sprintf(
						'PLG_DEBUG_QUERIES_TIME',
						sprintf('<span class="label ' . $labelClass .
'">%.2f&nbsp;ms</span>', $totalQueryTime)
					) . '</div>';

				if ($this->params->get('log-executed-sql', 0))
				{
					$this->writeToFile();
				}
			}
		}

		return implode('', $html);
	}

	/**
	 * Display memory usage.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayMemoryUsage()
	{
		$bytes = memory_get_usage();

		return '<span class="label label-default">' .
JHtml::_('number.bytes', $bytes) . '</span>'
			. ' (<span class="label label-default">'
			. number_format($bytes, 0, JText::_('DECIMALS_SEPARATOR'),
JText::_('THOUSANDS_SEPARATOR'))
			. ' '
			. JText::_('PLG_DEBUG_BYTES')
			. '</span>)';
	}

	/**
	 * Display logged queries.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayQueries()
	{
		$db  = $this->db;
		$log = $db->getLog();

		if (!$log)
		{
			return null;
		}

		$timings    = $db->getTimings();
		$callStacks = $db->getCallStacks();

		$db->setDebug(false);

		$selectQueryTypeTicker = array();
		$otherQueryTypeTicker  = array();

		$timing  = array();
		$maxtime = 0;

		if (isset($timings[0]))
		{
			$startTime         = $timings[0];
			$endTime           = $timings[count($timings) - 1];
			$totalBargraphTime = $endTime - $startTime;

			if ($totalBargraphTime > 0)
			{
				foreach ($log as $id => $query)
				{
					if (isset($timings[$id * 2 + 1]))
					{
						// Compute the query time: $timing[$k] = array( queryTime,
timeBetweenQueries ).
						$timing[$id] = array(
							($timings[$id * 2 + 1] - $timings[$id * 2]) * 1000,
							$id > 0 ? ($timings[$id * 2] - $timings[$id * 2 - 1]) * 1000 : 0,
						);
						$maxtime     = max($maxtime, $timing[$id]['0']);
					}
				}
			}
		}
		else
		{
			$startTime         = null;
			$totalBargraphTime = 1;
		}

		$bars           = array();
		$info           = array();
		$totalQueryTime = 0;
		$duplicates     = array();

		foreach ($log as $id => $query)
		{
			$did = md5($query);

			if (!isset($duplicates[$did]))
			{
				$duplicates[$did] = array();
			}

			$duplicates[$did][] = $id;

			if ($timings && isset($timings[$id * 2 + 1]))
			{
				// Compute the query time.
				$queryTime      = ($timings[$id * 2 + 1] - $timings[$id * 2]) * 1000;
				$totalQueryTime += $queryTime;

				// Run an EXPLAIN EXTENDED query on the SQL query if possible.
				$hasWarnings          = false;
				$hasWarningsInProfile = false;

				if (isset($this->explains[$id]))
				{
					$explain = $this->tableToHtml($this->explains[$id],
$hasWarnings);
				}
				else
				{
					$explain =
JText::sprintf('PLG_DEBUG_QUERY_EXPLAIN_NOT_POSSIBLE',
htmlspecialchars($query));
				}

				// Run a SHOW PROFILE query.
				$profile = '';

				if (isset($this->sqlShowProfileEach[$id]) &&
$db->getServerType() === 'mysql')
				{
					$profileTable = $this->sqlShowProfileEach[$id];
					$profile      = $this->tableToHtml($profileTable,
$hasWarningsInProfile);
				}

				// How heavy should the string length count: 0 - 1.
				$ratio     = 0.5;
				$timeScore = $queryTime / ((strlen($query) + 1) * $ratio) * 200;

				// Determine color of bargraph depending on query speed and presence of
warnings in EXPLAIN.
				if ($timeScore > 10)
				{
					$barClass   = 'bar-danger';
					$labelClass = 'label-important';
				}
				elseif ($hasWarnings || $timeScore > 5)
				{
					$barClass   = 'bar-warning';
					$labelClass = 'label-warning';
				}
				else
				{
					$barClass   = 'bar-success';
					$labelClass = 'label-success';
				}

				// Computes bargraph as follows: Position begin and end of the bar
relatively to whole execution time.
				// TODO: $prevBar is not used anywhere. Remove?
				$prevBar = $id && isset($bars[$id - 1]) ? $bars[$id - 1] : 0;

				$barPre   = round($timing[$id][1] / ($totalBargraphTime * 10), 4);
				$barWidth = round($timing[$id][0] / ($totalBargraphTime * 10), 4);
				$minWidth = 0.3;

				if ($barWidth < $minWidth)
				{
					$barPre -= ($minWidth - $barWidth);

					if ($barPre < 0)
					{
						$minWidth += $barPre;
						$barPre   = 0;
					}

					$barWidth = $minWidth;
				}

				$bars[$id] = (object) array(
					'class' => $barClass,
					'width' => $barWidth,
					'pre'   => $barPre,
					'tip'   => sprintf('%.2f ms', $queryTime),
				);
				$info[$id] = (object) array(
					'class'       => $labelClass,
					'explain'     => $explain,
					'profile'     => $profile,
					'hasWarnings' => $hasWarnings,
				);
			}
		}

		// Remove single queries from $duplicates.
		$total_duplicates = 0;

		foreach ($duplicates as $did => $dups)
		{
			if (count($dups) < 2)
			{
				unset($duplicates[$did]);
			}
			else
			{
				$total_duplicates += count($dups);
			}
		}

		// Fix first bar width.
		$minWidth = 0.3;

		if ($bars[0]->width < $minWidth && isset($bars[1]))
		{
			$bars[1]->pre -= ($minWidth - $bars[0]->width);

			if ($bars[1]->pre < 0)
			{
				$minWidth     += $bars[1]->pre;
				$bars[1]->pre = 0;
			}

			$bars[0]->width = $minWidth;
		}

		$memoryUsageNow = memory_get_usage();
		$list           = array();

		foreach ($log as $id => $query)
		{
			// Start query type ticker additions.
			$fromStart  = stripos($query, 'from');
			$whereStart = stripos($query, 'where', $fromStart);

			if ($whereStart === false)
			{
				$whereStart = stripos($query, 'order by', $fromStart);
			}

			if ($whereStart === false)
			{
				$whereStart = strlen($query) - 1;
			}

			$fromString = substr($query, 0, $whereStart);
			$fromString = str_replace(array("\t", "\n"), '
', $fromString);
			$fromString = trim($fromString);

			// Initialise the select/other query type counts the first time.
			if (!isset($selectQueryTypeTicker[$fromString]))
			{
				$selectQueryTypeTicker[$fromString] = 0;
			}

			if (!isset($otherQueryTypeTicker[$fromString]))
			{
				$otherQueryTypeTicker[$fromString] = 0;
			}

			// Increment the count.
			if (stripos($query, 'select') === 0)
			{
				$selectQueryTypeTicker[$fromString]++;
				unset($otherQueryTypeTicker[$fromString]);
			}
			else
			{
				$otherQueryTypeTicker[$fromString]++;
				unset($selectQueryTypeTicker[$fromString]);
			}

			$text = $this->highlightQuery($query);

			if ($timings && isset($timings[$id * 2 + 1]))
			{
				// Compute the query time.
				$queryTime = ($timings[$id * 2 + 1] - $timings[$id * 2]) * 1000;

				// Timing
				// Formats the output for the query time with EXPLAIN query results as
tooltip:
				$htmlTiming = '<div style="margin: 0 0
5px;"><span class="dbg-query-time">';
				$htmlTiming .= JText::sprintf(
					'PLG_DEBUG_QUERY_TIME',
					sprintf(
						'<span class="label
%s">%.2f&nbsp;ms</span>',
						$info[$id]->class,
						$timing[$id]['0']
					)
				);

				if ($timing[$id]['1'])
				{
					$htmlTiming .= ' ' . JText::sprintf(
							'PLG_DEBUG_QUERY_AFTER_LAST',
							sprintf('<span class="label
label-default">%.2f&nbsp;ms</span>',
$timing[$id]['1'])
						);
				}

				$htmlTiming .= '</span>';

				if (isset($callStacks[$id][0]['memory']))
				{
					$memoryUsed        = $callStacks[$id][0]['memory'][1] -
$callStacks[$id][0]['memory'][0];
					$memoryBeforeQuery = $callStacks[$id][0]['memory'][0];

					// Determine colour of query memory usage.
					if ($memoryUsed > 0.1 * $memoryUsageNow)
					{
						$labelClass = 'label-important';
					}
					elseif ($memoryUsed > 0.05 * $memoryUsageNow)
					{
						$labelClass = 'label-warning';
					}
					else
					{
						$labelClass = 'label-success';
					}

					$htmlTiming .= ' ' . '<span
class="dbg-query-memory">'
						. JText::sprintf(
							'PLG_DEBUG_MEMORY_USED_FOR_QUERY',
							sprintf('<span class="label ' . $labelClass .
'">%.3f&nbsp;MB</span>', $memoryUsed /
1048576),
							sprintf('<span class="label
label-default">%.3f&nbsp;MB</span>',
$memoryBeforeQuery / 1048576)
						)
						. '</span>';

					if ($callStacks[$id][0]['memory'][2] !== null)
					{
						// Determine colour of number or results.
						$resultsReturned = $callStacks[$id][0]['memory'][2];

						if ($resultsReturned > 3000)
						{
							$labelClass = 'label-important';
						}
						elseif ($resultsReturned > 1000)
						{
							$labelClass = 'label-warning';
						}
						elseif ($resultsReturned == 0)
						{
							$labelClass = '';
						}
						else
						{
							$labelClass = 'label-success';
						}

						$htmlResultsReturned = '<span class="label ' .
$labelClass . '">' . (int) $resultsReturned .
'</span>';
						$htmlTiming          .= ' <span
class="dbg-query-rowsnumber">'
							. JText::sprintf('PLG_DEBUG_ROWS_RETURNED_BY_QUERY',
$htmlResultsReturned) . '</span>';
					}
				}

				$htmlTiming .= '</div>';

				// Bar.
				$htmlBar = $this->renderBars($bars, 'query', $id);

				// Profile query.
				$title = JText::_('PLG_DEBUG_PROFILE');

				if (!$info[$id]->profile)
				{
					$title = '<span class="dbg-noprofile">' .
$title . '</span>';
				}

				$htmlProfile = $info[$id]->profile ?:
JText::_('PLG_DEBUG_NO_PROFILE');

				$htmlAccordions = JHtml::_(
					'bootstrap.startAccordion', 'dbg_query_' . $id,
array(
						'active' => $info[$id]->hasWarnings ?
('dbg_query_explain_' . $id) : '',
					)
				);

				$htmlAccordions .= JHtml::_('bootstrap.addSlide',
'dbg_query_' . $id, JText::_('PLG_DEBUG_EXPLAIN'),
'dbg_query_explain_' . $id)
					. $info[$id]->explain
					. JHtml::_('bootstrap.endSlide');

				$htmlAccordions .= JHtml::_('bootstrap.addSlide',
'dbg_query_' . $id, $title, 'dbg_query_profile_' . $id)
					. $htmlProfile
					. JHtml::_('bootstrap.endSlide');

				// Call stack and back trace.
				if (isset($callStacks[$id]))
				{
					$htmlAccordions .= JHtml::_('bootstrap.addSlide',
'dbg_query_' . $id, JText::_('PLG_DEBUG_CALL_STACK'),
'dbg_query_callstack_' . $id)
						. $this->renderCallStack($callStacks[$id])
						. JHtml::_('bootstrap.endSlide');
				}

				$htmlAccordions .= JHtml::_('bootstrap.endAccordion');

				$did = md5($query);

				if (isset($duplicates[$did]))
				{
					$dups = array();

					foreach ($duplicates[$did] as $dup)
					{
						if ($dup != $id)
						{
							$dups[] = '<a class="alert-link"
href="#dbg-query-' . ($dup + 1) . '">#' . ($dup
+ 1) . '</a>';
						}
					}

					$htmlQuery = '<div class="alert
alert-error">' .
JText::_('PLG_DEBUG_QUERY_DUPLICATES') . ': ' .
implode('&nbsp; ', $dups) . '</div>'
						. '<pre class="alert" title="' .
htmlspecialchars(JText::_('PLG_DEBUG_QUERY_DUPLICATES_FOUND'),
ENT_COMPAT, 'UTF-8') . '">' . $text .
'</pre>';
				}
				else
				{
					$htmlQuery = '<pre>' . $text .
'</pre>';
				}

				$list[] = '<a name="dbg-query-' . ($id + 1) .
'"></a>'
					. $htmlTiming
					. $htmlBar
					. $htmlQuery
					. $htmlAccordions;
			}
			else
			{
				$list[] = '<pre>' . $text . '</pre>';
			}
		}

		$totalTime = 0;

		foreach (JProfiler::getInstance('Application')->getMarks()
as $mark)
		{
			$totalTime += $mark->time;
		}

		if ($totalQueryTime > ($totalTime * 0.25))
		{
			$labelClass = 'label-important';
		}
		elseif ($totalQueryTime < ($totalTime * 0.15))
		{
			$labelClass = 'label-success';
		}
		else
		{
			$labelClass = 'label-warning';
		}

		if ($this->totalQueries === 0)
		{
			$this->totalQueries = $db->getCount();
		}

		$html = array();

		$html[] = '<h4>' .
JText::sprintf('PLG_DEBUG_QUERIES_LOGGED',
$this->totalQueries)
			. sprintf(' <span class="label ' . $labelClass .
'">%.2f&nbsp;ms</span>', $totalQueryTime) .
'</h4><br />';

		if ($total_duplicates)
		{
			$html[] = '<div class="alert alert-error">'
				. '<h4>' .
JText::sprintf('PLG_DEBUG_QUERY_DUPLICATES_TOTAL_NUMBER',
$total_duplicates) . '</h4>';

			foreach ($duplicates as $dups)
			{
				$links = array();

				foreach ($dups as $dup)
				{
					$links[] = '<a class="alert-link"
href="#dbg-query-' . ($dup + 1) . '">#' . ($dup
+ 1) . '</a>';
				}

				$html[] = '<div>' .
JText::sprintf('PLG_DEBUG_QUERY_DUPLICATES_NUMBER',
count($links)) . ': ' . implode('&nbsp; ', $links)
. '</div>';
			}

			$html[] = '</div>';
		}

		$html[] = '<ol><li>' . implode('<hr
/></li><li>', $list) . '<hr
/></li></ol>';

		if (!$this->params->get('query_types', 1))
		{
			return implode('', $html);
		}

		// Get the totals for the query types.
		$totalSelectQueryTypes = count($selectQueryTypeTicker);
		$totalOtherQueryTypes  = count($otherQueryTypeTicker);
		$totalQueryTypes       = $totalSelectQueryTypes + $totalOtherQueryTypes;

		$html[] = '<h4>' .
JText::sprintf('PLG_DEBUG_QUERY_TYPES_LOGGED', $totalQueryTypes)
. '</h4>';

		if ($totalSelectQueryTypes)
		{
			$html[] = '<h5>' .
JText::_('PLG_DEBUG_SELECT_QUERIES') . '</h5>';

			arsort($selectQueryTypeTicker);

			$list = array();

			foreach ($selectQueryTypeTicker as $query => $occurrences)
			{
				$list[] = '<pre>'
					. JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES',
$this->highlightQuery($query), $occurrences)
					. '</pre>';
			}

			$html[] = '<ol><li>' .
implode('</li><li>', $list) .
'</li></ol>';
		}

		if ($totalOtherQueryTypes)
		{
			$html[] = '<h5>' .
JText::_('PLG_DEBUG_OTHER_QUERIES') . '</h5>';

			arsort($otherQueryTypeTicker);

			$list = array();

			foreach ($otherQueryTypeTicker as $query => $occurrences)
			{
				$list[] = '<pre>'
					. JText::sprintf('PLG_DEBUG_QUERY_TYPE_AND_OCCURRENCES',
$this->highlightQuery($query), $occurrences)
					. '</pre>';
			}

			$html[] = '<ol><li>' .
implode('</li><li>', $list) .
'</li></ol>';
		}

		return implode('', $html);
	}

	/**
	 * Render the bars.
	 *
	 * @param   array    &$bars  Array of bar data
	 * @param   string   $class  Optional class for items
	 * @param   integer  $id     Id if the bar to highlight
	 *
	 * @return  string
	 *
	 * @since   3.1.2
	 */
	protected function renderBars(&$bars, $class = '', $id =
null)
	{
		$html = array();

		foreach ($bars as $i => $bar)
		{
			if (isset($bar->pre) && $bar->pre)
			{
				$html[] = '<div class="dbg-bar-spacer"
style="width:' . $bar->pre .
'%;"></div>';
			}

			$barClass = trim('bar dbg-bar progress-bar ' .
(isset($bar->class) ? $bar->class : ''));

			if ($id !== null && $i == $id)
			{
				$barClass .= ' dbg-bar-active';
			}

			$tip = empty($bar->tip) ? '' : ' title="' .
htmlspecialchars($bar->tip, ENT_COMPAT, 'UTF-8') .
'"';

			$html[] = '<a class="bar dbg-bar ' . $barClass .
'"' . $tip . ' style="width: '
				. $bar->width . '%;" href="#dbg-' . $class .
'-' . ($i + 1) . '"></a>';
		}

		return '<div class="progress dbg-bars dbg-bars-' .
$class . '">' . implode('', $html) .
'</div>';
	}

	/**
	 * Render an HTML table based on a multi-dimensional array.
	 *
	 * @param   array    $table         An array of tabular data.
	 * @param   boolean  &$hasWarnings  Changes value to true if warnings
are displayed, otherwise untouched
	 *
	 * @return  string
	 *
	 * @since   3.1.2
	 */
	protected function tableToHtml($table, &$hasWarnings)
	{
		if (!$table)
		{
			return null;
		}

		$html = array();

		$html[] = '<table class="table table-striped
dbg-query-table">';
		$html[] = '<thead>';
		$html[] = '<tr>';

		foreach (array_keys($table[0]) as $k)
		{
			$html[] = '<th>' . htmlspecialchars($k) .
'</th>';
		}

		$html[]    = '</tr>';
		$html[]    = '</thead>';
		$html[]    = '<tbody>';
		$durations = array();

		foreach ($table as $tr)
		{
			if (isset($tr['Duration']))
			{
				$durations[] = $tr['Duration'];
			}
		}

		rsort($durations, SORT_NUMERIC);

		foreach ($table as $tr)
		{
			$html[] = '<tr>';

			foreach ($tr as $k => $td)
			{
				if ($td === null)
				{
					// Display null's as 'NULL'.
					$td = 'NULL';
				}

				// Treat special columns.
				if ($k === 'Duration')
				{
					if ($td >= 0.001 && ($td == $durations[0] ||
(isset($durations[1]) && $td == $durations[1])))
					{
						// Duration column with duration value of more than 1 ms and within 2
top duration in SQL engine: Highlight warning.
						$html[]      = '<td class="dbg-warning">';
						$hasWarnings = true;
					}
					else
					{
						$html[] = '<td>';
					}

					// Display duration in milliseconds with the unit instead of seconds.
					$html[] = sprintf('%.2f&nbsp;ms', $td * 1000);
				}
				elseif ($k === 'Error')
				{
					// An error in the EXPLAIN query occurred, display it instead of the
result (means original query had syntax error most probably).
					$html[]      = '<td class="dbg-warning">' .
htmlspecialchars($td);
					$hasWarnings = true;
				}
				elseif ($k === 'key')
				{
					if ($td === 'NULL')
					{
						// Displays query parts which don't use a key with warning:
						$html[]      = '<td><strong>' . '<span
class="dbg-warning" title="'
							.
htmlspecialchars(JText::_('PLG_DEBUG_WARNING_NO_INDEX_DESC'),
ENT_COMPAT, 'UTF-8') . '">'
							. JText::_('PLG_DEBUG_WARNING_NO_INDEX') .
'</span>' . '</strong>';
						$hasWarnings = true;
					}
					else
					{
						$html[] = '<td><strong>' .
htmlspecialchars($td) . '</strong>';
					}
				}
				elseif ($k === 'Extra')
				{
					$htmlTd = htmlspecialchars($td);

					// Replace spaces with &nbsp; (non-breaking spaces) for less tall
tables displayed.
					$htmlTd = preg_replace('/([^;]) /',
'\1&nbsp;', $htmlTd);

					// Displays warnings for "Using filesort":
					$htmlTdWithWarnings = str_replace(
						'Using&nbsp;filesort',
						'<span class="dbg-warning" title="'
						.
htmlspecialchars(JText::_('PLG_DEBUG_WARNING_USING_FILESORT_DESC'),
ENT_COMPAT, 'UTF-8') . '">'
						. JText::_('PLG_DEBUG_WARNING_USING_FILESORT') .
'</span>',
						$htmlTd
					);

					if ($htmlTdWithWarnings !== $htmlTd)
					{
						$hasWarnings = true;
					}

					$html[] = '<td>' . $htmlTdWithWarnings;
				}
				else
				{
					$html[] = '<td>' . htmlspecialchars($td);
				}

				$html[] = '</td>';
			}

			$html[] = '</tr>';
		}

		$html[] = '</tbody>';
		$html[] = '</table>';

		return implode('', $html);
	}

	/**
	 * Disconnect handler for database to collect profiling and explain
information.
	 *
	 * @param   JDatabaseDriver  &$db  Database object.
	 *
	 * @return  void
	 *
	 * @since   3.1.2
	 */
	public function mysqlDisconnectHandler(&$db)
	{
		$db->setDebug(false);

		$this->totalQueries = $db->getCount();

		$dbVersion5037 = $db->getServerType() === 'mysql' &&
version_compare($db->getVersion(), '5.0.37',
'>=');

		if ($dbVersion5037)
		{
			try
			{
				// Check if profiling is enabled.
				$db->setQuery("SHOW VARIABLES LIKE
'have_profiling'");
				$hasProfiling = $db->loadResult();

				if ($hasProfiling)
				{
					// Run a SHOW PROFILE query.
					$db->setQuery('SHOW PROFILES');
					$this->sqlShowProfiles = $db->loadAssocList();

					if ($this->sqlShowProfiles)
					{
						foreach ($this->sqlShowProfiles as $qn)
						{
							// Run SHOW PROFILE FOR QUERY for each query where a profile is
available (max 100).
							$db->setQuery('SHOW PROFILE FOR QUERY ' . (int)
$qn['Query_ID']);
							$this->sqlShowProfileEach[(int) ($qn['Query_ID'] - 1)]
= $db->loadAssocList();
						}
					}
				}
				else
				{
					$this->sqlShowProfileEach[0] = array(array('Error' =>
'MySql have_profiling = off'));
				}
			}
			catch (Exception $e)
			{
				$this->sqlShowProfileEach[0] = array(array('Error' =>
$e->getMessage()));
			}
		}

		if (in_array($db->getServerType(), array('mysql',
'postgresql'), true))
		{
			$log = $db->getLog();

			foreach ($log as $k => $query)
			{
				$dbVersion56 = $db->getServerType() === 'mysql' &&
version_compare($db->getVersion(), '5.6', '>=');
				$dbVersion80 = $db->getServerType() === 'mysql' &&
version_compare($db->getVersion(), '8.0', '>=');

				if ($dbVersion80)
				{
					$dbVersion56 = false;
				}

				if ((stripos($query, 'select') === 0) || ($dbVersion56
&& ((stripos($query, 'delete') === 0) || (stripos($query,
'update') === 0))))
				{
					try
					{
						$db->setQuery('EXPLAIN ' . ($dbVersion56 ?
'EXTENDED ' : '') . $query);
						$this->explains[$k] = $db->loadAssocList();
					}
					catch (Exception $e)
					{
						$this->explains[$k] = array(array('Error' =>
$e->getMessage()));
					}
				}
			}
		}
	}

	/**
	 * Displays errors in language files.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayLanguageFilesInError()
	{
		$errorfiles = JFactory::getLanguage()->getErrorFiles();

		if (!count($errorfiles))
		{
			return '<p>' . JText::_('JNONE') .
'</p>';
		}

		$html = array();

		$html[] = '<ul>';

		foreach ($errorfiles as $file => $error)
		{
			$html[] = '<li>' . $this->formatLink($file) .
str_replace($file, '', $error) . '</li>';
		}

		$html[] = '</ul>';

		return implode('', $html);
	}

	/**
	 * Display loaded language files.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayLanguageFilesLoaded()
	{
		$html = array();

		$html[] = '<ul>';

		foreach (JFactory::getLanguage()->getPaths() as /* $extension => */
$files)
		{
			foreach ($files as $file => $status)
			{
				$html[] = '<li>';

				$html[] = $status
					? JText::_('PLG_DEBUG_LANG_LOADED')
					: JText::_('PLG_DEBUG_LANG_NOT_LOADED');

				$html[] = ' : ';
				$html[] = $this->formatLink($file);
				$html[] = '</li>';
			}
		}

		$html[] = '</ul>';

		return implode('', $html);
	}

	/**
	 * Display untranslated language strings.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function displayUntranslatedStrings()
	{
		$stripFirst = $this->params->get('strip-first', 1);
		$stripPref  = $this->params->get('strip-prefix');
		$stripSuff  = $this->params->get('strip-suffix');

		$orphans = JFactory::getLanguage()->getOrphans();

		if (!count($orphans))
		{
			return '<p>' . JText::_('JNONE') .
'</p>';
		}

		ksort($orphans, SORT_STRING);

		$guesses = array();

		foreach ($orphans as $key => $occurance)
		{
			if (is_array($occurance) && isset($occurance[0]))
			{
				$info = $occurance[0];
				$file = $info['file'] ?: '';

				if (!isset($guesses[$file]))
				{
					$guesses[$file] = array();
				}

				// Prepare the key.
				if (($pos = strpos($info['string'], '=')) > 0)
				{
					$parts = explode('=', $info['string']);
					$key   = $parts[0];
					$guess = $parts[1];
				}
				else
				{
					$guess = str_replace('_', ' ',
$info['string']);

					if ($stripFirst)
					{
						$parts = explode(' ', $guess);

						if (count($parts) > 1)
						{
							array_shift($parts);
							$guess = implode(' ', $parts);
						}
					}

					$guess = trim($guess);

					if ($stripPref)
					{
						$guess = trim(preg_replace(chr(1) . '^' . $stripPref .
chr(1) . 'i', '', $guess));
					}

					if ($stripSuff)
					{
						$guess = trim(preg_replace(chr(1) . $stripSuff . '$' .
chr(1) . 'i', '', $guess));
					}
				}

				$key = strtoupper(trim($key));
				$key = preg_replace('#\s+#', '_', $key);
				$key = preg_replace('#\W#', '', $key);

				// Prepare the text.
				$guesses[$file][] = $key . '="' . $guess .
'"';
			}
		}

		$html = array();

		foreach ($guesses as $file => $keys)
		{
			$html[] = "\n\n# " . ($file ? $this->formatLink($file) :
JText::_('PLG_DEBUG_UNKNOWN_FILE')) . "\n\n";
			$html[] = implode("\n", $keys);
		}

		return '<pre>' . implode('', $html) .
'</pre>';
	}

	/**
	 * Simple highlight for SQL queries.
	 *
	 * @param   string  $query  The query to highlight.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function highlightQuery($query)
	{
		$newlineKeywords =
'#\b(FROM|LEFT|INNER|OUTER|WHERE|SET|VALUES|ORDER|GROUP|HAVING|LIMIT|ON|AND|CASE)\b#i';

		$query = htmlspecialchars($query, ENT_QUOTES);

		$query = preg_replace($newlineKeywords, '<br
/>&#160;&#160;\\0', $query);

		$regex = array(

			// Tables are identified by the prefix.
			'/(=)/'                                        =>
'<b class="dbg-operator">$1</b>',

			// All uppercase words have a special meaning.
			'/(?<!\w|>)([A-Z_]{2,})(?!\w)/x'               =>
'<span class="dbg-command">$1</span>',

			// Tables are identified by the prefix.
			'/(' . $this->db->getPrefix() . '[a-z_0-9]+)/'
=> '<span class="dbg-table">$1</span>',

		);

		$query = preg_replace(array_keys($regex), array_values($regex), $query);

		$query = str_replace('*', '<b style="color:
red;">*</b>', $query);

		return $query;
	}

	/**
	 * Render the backtrace.
	 *
	 * Stolen from JError to prevent it's removal.
	 *
	 * @param   Exception  $error  The Exception object to be rendered.
	 *
	 * @return  string     Rendered backtrace.
	 *
	 * @since   2.5
	 */
	protected function renderBacktrace($error)
	{
		return JLayoutHelper::render('joomla.error.backtrace',
array('backtrace' => $error->getTrace()));
	}

	/**
	 * Replaces the Joomla! root with "JROOT" to improve
readability.
	 * Formats a link with a special value xdebug.file_link_format
	 * from the php.ini file.
	 *
	 * @param   string  $file  The full path to the file.
	 * @param   string  $line  The line number.
	 *
	 * @return  string
	 *
	 * @since   2.5
	 */
	protected function formatLink($file, $line = '')
	{
		return JHtml::_('debug.xdebuglink', $file, $line);
	}

	/**
	 * Store log messages so they can be displayed later.
	 * This function is passed log entries by JLogLoggerCallback.
	 *
	 * @param   JLogEntry  $entry  A log entry.
	 *
	 * @return  void
	 *
	 * @since   3.1
	 */
	public function logger(JLogEntry $entry)
	{
		$this->logEntries[] = $entry;
	}

	/**
	 * Display log messages.
	 *
	 * @return  string
	 *
	 * @since   3.1
	 */
	protected function displayLogs()
	{
		$priorities = array(
			JLog::EMERGENCY => '<span class="badge
badge-important">EMERGENCY</span>',
			JLog::ALERT     => '<span class="badge
badge-important">ALERT</span>',
			JLog::CRITICAL  => '<span class="badge
badge-important">CRITICAL</span>',
			JLog::ERROR     => '<span class="badge
badge-important">ERROR</span>',
			JLog::WARNING   => '<span class="badge
badge-warning">WARNING</span>',
			JLog::NOTICE    => '<span class="badge
badge-info">NOTICE</span>',
			JLog::INFO      => '<span class="badge
badge-info">INFO</span>',
			JLog::DEBUG     => '<span
class="badge">DEBUG</span>',
		);

		$out = '';

		$logEntriesTotal = count($this->logEntries);

		// SQL log entries
		$showExecutedSQL = $this->params->get('log-executed-sql',
0);

		if (!$showExecutedSQL)
		{
			$logEntriesDatabasequery = count(
				array_filter(
					$this->logEntries, function ($logEntry)
					{
						return $logEntry->category === 'databasequery';
					}
				)
			);
			$logEntriesTotal         -= $logEntriesDatabasequery;
		}

		// Deprecated log entries
		$logEntriesDeprecated = count(
			array_filter(
				$this->logEntries, function ($logEntry)
				{
					return $logEntry->category === 'deprecated';
				}
			)
		);
		$showDeprecated       =
$this->params->get('log-deprecated', 0);

		if (!$showDeprecated)
		{
			$logEntriesTotal -= $logEntriesDeprecated;
		}

		$showEverything = $this->params->get('log-everything',
0);

		$out .= '<h4>' .
JText::sprintf('PLG_DEBUG_LOGS_LOGGED', $logEntriesTotal) .
'</h4><br />';

		if ($showDeprecated && $logEntriesDeprecated > 0)
		{
			$out .= '
			<div class="alert alert-warning">
				<h4>' .
JText::sprintf('PLG_DEBUG_LOGS_DEPRECATED_FOUND_TITLE',
$logEntriesDeprecated) . '</h4>
				<div>' .
JText::_('PLG_DEBUG_LOGS_DEPRECATED_FOUND_TEXT') .
'</div>
			</div>
			<br />';
		}

		$out   .= '<ol>';
		$count = 1;

		foreach ($this->logEntries as $entry)
		{
			// Don't show database queries if not selected.
			if (!$showExecutedSQL && $entry->category ===
'databasequery')
			{
				continue;
			}

			// Don't show deprecated logs if not selected.
			if (!$showDeprecated && $entry->category ===
'deprecated')
			{
				continue;
			}

			// Don't show everything logs if not selected.
			if (!$showEverything && !in_array($entry->category,
array('deprecated', 'databasequery'), true))
			{
				continue;
			}

			$out .= '<li id="dbg_logs_' . $count .
'">';
			$out .= '<h5>' . $priorities[$entry->priority] .
' ' . $entry->category . '</h5><br />
				<pre>' . $entry->message . '</pre>';

			if ($entry->callStack)
			{
				$out .= JHtml::_('bootstrap.startAccordion',
'dbg_logs_' . $count, array('active' =>
''));
				$out .= JHtml::_('bootstrap.addSlide', 'dbg_logs_'
. $count, JText::_('PLG_DEBUG_CALL_STACK'),
'dbg_logs_backtrace_' . $count);
				$out .= $this->renderCallStack($entry->callStack);
				$out .= JHtml::_('bootstrap.endSlide');
				$out .= JHtml::_('bootstrap.endAccordion');
			}

			$out .= '<hr /></li>';
			$count++;
		}

		$out .= '</ol>';

		return $out;
	}

	/**
	 * Renders call stack and back trace in HTML.
	 *
	 * @param   array  $callStack  The call stack and back trace array.
	 *
	 * @return  string  The call stack and back trace in HMTL format.
	 *
	 * @since   3.5
	 */
	protected function renderCallStack(array $callStack = array())
	{
		$htmlCallStack = '';

		if ($callStack !== null)
		{
			$htmlCallStack .= '<div>';
			$htmlCallStack .= '<table class="table table-striped
dbg-query-table">';
			$htmlCallStack .= '<thead>';
			$htmlCallStack .= '<tr>';
			$htmlCallStack .= '<th>#</th>';
			$htmlCallStack .= '<th>' .
JText::_('PLG_DEBUG_CALL_STACK_CALLER') .
'</th>';
			$htmlCallStack .= '<th>' .
JText::_('PLG_DEBUG_CALL_STACK_FILE_AND_LINE') .
'</th>';
			$htmlCallStack .= '</tr>';
			$htmlCallStack .= '</thead>';
			$htmlCallStack .= '<tbody>';

			$count = count($callStack);

			foreach ($callStack as $call)
			{
				// Dont' back trace log classes.
				if (isset($call['class']) &&
strpos($call['class'], 'JLog') !== false)
				{
					$count--;
					continue;
				}

				$htmlCallStack .= '<tr>';

				$htmlCallStack .= '<td>' . $count .
'</td>';

				$htmlCallStack .= '<td>';

				if (isset($call['class']))
				{
					// If entry has Class/Method print it.
					$htmlCallStack .= htmlspecialchars($call['class'] .
$call['type'] . $call['function']) . '()';
				}
				else
				{
					if (isset($call['args']))
					{
						// If entry has args is a require/include.
						$htmlCallStack .= htmlspecialchars($call['function']) .
' ' . $this->formatLink($call['args'][0]);
					}
					else
					{
						// It's a function.
						$htmlCallStack .= htmlspecialchars($call['function']) .
'()';
					}
				}

				$htmlCallStack .= '</td>';

				$htmlCallStack .= '<td>';

				// If entry doesn't have line and number the next is a
call_user_func.
				if (!isset($call['file']) &&
!isset($call['line']))
				{
					$htmlCallStack .=
JText::_('PLG_DEBUG_CALL_STACK_SAME_FILE');
				}
				// If entry has file and line print it.
				else
				{
					$htmlCallStack .=
$this->formatLink(htmlspecialchars($call['file']),
htmlspecialchars($call['line']));
				}

				$htmlCallStack .= '</td>';

				$htmlCallStack .= '</tr>';
				$count--;
			}

			$htmlCallStack .= '</tbody>';
			$htmlCallStack .= '</table>';
			$htmlCallStack .= '</div>';

			if (!$this->linkFormat)
			{
				$htmlCallStack .= '<div>[<a
href="https://xdebug.org/docs/all_settings#file_link_format"
target="_blank" rel="noopener noreferrer">';
				$htmlCallStack .= JText::_('PLG_DEBUG_LINK_FORMAT') .
'</a>]</div>';
			}
		}

		return $htmlCallStack;
	}

	/**
	 * Pretty print JSON with colors.
	 *
	 * @param   string  $json  The json raw string.
	 *
	 * @return  string  The json string pretty printed.
	 *
	 * @since   3.5
	 */
	protected function prettyPrintJSON($json = '')
	{
		// In PHP 5.4.0 or later we have pretty print option.
		if (version_compare(PHP_VERSION, '5.4', '>='))
		{
			$json = json_encode($json, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT);
		}

		// Escape HTML in session vars
		$json = htmlentities($json);

		// Add some colors
		$json = preg_replace('#"([^"]+)":#',
'<span class=\'black\'>"</span><span
class=\'green\'>$1</span><span
class=\'black\'>"</span>:', $json);
		$json = preg_replace('#"(|[^"]+)"(\n|\r\n|,)#',
'<span
class=\'grey\'>"$1"</span>$2', $json);
		$json = str_replace('null,', '<span
class=\'blue\'>null</span>,', $json);

		return $json;
	}

	/**
	 * Write query to the log file
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	protected function writeToFile()
	{
		$app    = JFactory::getApplication();
		$domain = $app->isClient('site') ? 'site' :
'admin';
		$input  = $app->input;
		$file   = $app->get('log_path') . '/' . $domain .
'_' . $input->get('option') .
$input->get('view') . $input->get('layout') .
'.sql.php';

		// Get the queries from log.
		$current = '';
		$db      = $this->db;
		$log     = $db->getLog();
		$timings = $db->getTimings();

		foreach ($log as $id => $query)
		{
			if (isset($timings[$id * 2 + 1]))
			{
				$temp    = str_replace('`', '', $log[$id]);
				$temp    = str_replace(array("\t", "\n",
"\r\n"), ' ', $temp);
				$current .= $temp . ";\n";
			}
		}

		if (JFile::exists($file))
		{
			JFile::delete($file);
		}

		$head   = array('#');
		$head[] = '#<?php die(\'Forbidden.\'); ?>';
		$head[] = '#Date: ' . gmdate('Y-m-d H:i:s') . '
UTC';
		$head[] = '#Software: ' . \JPlatform::getLongVersion();
		$head[] = "\n";

		// Write new file.
		JFile::write($file, implode("\n", $head) . $current);
	}
}
system/debug/debug.xml000064400000017076147357022250011010 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_debug</name>
	<author>Joomla! Project</author>
	<creationDate>December 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_DEBUG_XML_DESCRIPTION</description>
	<files>
		<filename plugin="debug">debug.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_debug.ini</language>
		<language
tag="en-GB">en-GB.plg_system_debug.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="filter_groups"
					type="usergrouplist"
					label="PLG_DEBUG_FIELD_ALLOWED_GROUPS_LABEL"
					description="PLG_DEBUG_FIELD_ALLOWED_GROUPS_DESC"
					multiple="true"
					filter="int_array"
					size="10"
				/>

				<field
					name="session"
					type="radio"
					label="PLG_DEBUG_FIELD_SESSION_LABEL"
					description="PLG_DEBUG_FIELD_SESSION_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="profile"
					type="radio"
					label="PLG_DEBUG_FIELD_PROFILING_LABEL"
					description="PLG_DEBUG_FIELD_PROFILING_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="queries"
					type="radio"
					label="PLG_DEBUG_FIELD_QUERIES_LABEL"
					description="PLG_DEBUG_FIELD_QUERIES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="query_types"
					type="radio"
					label="PLG_DEBUG_FIELD_QUERY_TYPES_LABEL"
					description="PLG_DEBUG_FIELD_QUERY_TYPES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="memory"
					type="radio"
					label="PLG_DEBUG_FIELD_MEMORY_LABEL"
					description="PLG_DEBUG_FIELD_MEMORY_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="logs"
					type="radio"
					label="PLG_DEBUG_FIELD_LOGS_LABEL"
					description="PLG_DEBUG_FIELD_LOGS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="log_priorities"
					type="list"
					label="PLG_DEBUG_FIELD_LOG_PRIORITIES_LABEL"
					description="PLG_DEBUG_FIELD_LOG_PRIORITIES_DESC"
					multiple="true"
					default="all"
					>
					<option
value="all">PLG_DEBUG_FIELD_LOG_PRIORITIES_ALL</option>
					<option
value="emergency">PLG_DEBUG_FIELD_LOG_PRIORITIES_EMERGENCY</option>
					<option
value="alert">PLG_DEBUG_FIELD_LOG_PRIORITIES_ALERT</option>
					<option
value="critical">PLG_DEBUG_FIELD_LOG_PRIORITIES_CRITICAL</option>
					<option
value="error">PLG_DEBUG_FIELD_LOG_PRIORITIES_ERROR</option>
					<option
value="warning">PLG_DEBUG_FIELD_LOG_PRIORITIES_WARNING</option>
					<option
value="notice">PLG_DEBUG_FIELD_LOG_PRIORITIES_NOTICE</option>
					<option
value="info">PLG_DEBUG_FIELD_LOG_PRIORITIES_INFO</option>
					<option
value="debug">PLG_DEBUG_FIELD_LOG_PRIORITIES_DEBUG</option>
				</field>

				<field
					name="log_categories"
					type="text"
					label="PLG_DEBUG_FIELD_LOG_CATEGORIES_LABEL"
					description="PLG_DEBUG_FIELD_LOG_CATEGORIES_DESC"
					size="60"
				/>

				<field
					name="log_category_mode"
					type="radio"
					label="PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_LABEL"
					description="PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno btn-group-reversed"
					>
					<option
value="0">PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_INCLUDE</option>
					<option
value="1">PLG_DEBUG_FIELD_LOG_CATEGORY_MODE_EXCLUDE</option>
				</field>

				<field
					name="refresh_assets"
					type="radio"
					label="PLG_DEBUG_FIELD_REFRESH_ASSETS_LABEL"
					description="PLG_DEBUG_FIELD_REFRESH_ASSETS_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>

			<fieldset
				name="language"
				label="PLG_DEBUG_LANGUAGE_FIELDSET_LABEL"
				>

				<field
					name="language_errorfiles"
					type="radio"
					label="PLG_DEBUG_FIELD_LANGUAGE_ERRORFILES_LABEL"
					description="PLG_DEBUG_FIELD_LANGUAGE_ERRORFILES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="language_files"
					type="radio"
					label="PLG_DEBUG_FIELD_LANGUAGE_FILES_LABEL"
					description="PLG_DEBUG_FIELD_LANGUAGE_FILES_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="language_strings"
					type="radio"
					label="PLG_DEBUG_FIELD_LANGUAGE_STRING_LABEL"
					description="PLG_DEBUG_FIELD_LANGUAGE_STRING_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="strip-first"
					type="radio"
					label="PLG_DEBUG_FIELD_STRIP_FIRST_LABEL"
					description="PLG_DEBUG_FIELD_STRIP_FIRST_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="strip-prefix"
					type="textarea"
					label="PLG_DEBUG_FIELD_STRIP_PREFIX_LABEL"
					description="PLG_DEBUG_FIELD_STRIP_PREFIX_DESC"
					cols="30"
					rows="4"
				/>

				<field
					name="strip-suffix"
					type="textarea"
					label="PLG_DEBUG_FIELD_STRIP_SUFFIX_LABEL"
					description="PLG_DEBUG_FIELD_STRIP_SUFFIX_DESC"
					cols="30"
					rows="4"
				/>
			</fieldset>

			<fieldset
				name="logging"
				label="PLG_DEBUG_LOGGING_FIELDSET_LABEL"
				>
				<field
					name="log-deprecated"
					type="radio"
					label="PLG_DEBUG_FIELD_LOG_DEPRECATED_LABEL"
					description="PLG_DEBUG_FIELD_LOG_DEPRECATED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="log-everything"
					type="radio"
					label="PLG_DEBUG_FIELD_LOG_EVERYTHING_LABEL"
					description="PLG_DEBUG_FIELD_LOG_EVERYTHING_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="log-executed-sql"
					type="radio"
					label="PLG_DEBUG_FIELD_EXECUTEDSQL_LABEL"
					description="PLG_DEBUG_FIELD_EXECUTEDSQL_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
system/fields/fields.php000064400000031375147357022250011335
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.Fields
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Form\Form;
use Joomla\Registry\Registry;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Multilanguage;

JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR .
'/components/com_fields/helpers/fields.php');

/**
 * Fields Plugin
 *
 * @since  3.7
 */
class PlgSystemFields extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.7.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Normalizes the request data.
	 *
	 * @param   string  $context  The context
	 * @param   object  $data     The object
	 * @param   Form    $form     The form
	 *
	 * @return  void
	 *
	 * @since   3.8.7
	 */
	public function onContentNormaliseRequestData($context, $data, Form $form)
	{
		if (!FieldsHelper::extract($context, $data))
		{
			return true;
		}

		// Loop over all fields
		foreach ($form->getGroup('com_fields') as $field)
		{
			if ($field->disabled === true)
			{
				/**
				 * Disabled fields should NEVER be added to the request as
				 * they should NEVER be added by the browser anyway so nothing to check
against
				 * as "disabled" means no interaction at all.
				 */

				// Make sure the data object has an entry before delete it
				if (isset($data->com_fields[$field->fieldname]))
				{
					unset($data->com_fields[$field->fieldname]);
				}

				continue;
			}

			// Make sure the data object has an entry
			if (isset($data->com_fields[$field->fieldname]))
			{
				continue;
			}

			// Set a default value for the field
			$data->com_fields[$field->fieldname] = false;
		}
	}

	/**
	 * The save event.
	 *
	 * @param   string   $context  The context
	 * @param   JTable   $item     The table
	 * @param   boolean  $isNew    Is new item
	 * @param   array    $data     The validated data
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterSave($context, $item, $isNew, $data =
array())
	{
		// Check if data is an array and the item has an id
		if (!is_array($data) || empty($item->id) ||
empty($data['com_fields']))
		{
			return true;
		}

		// Create correct context for category
		if ($context == 'com_categories.category')
		{
			$context = $item->extension . '.categories';

			// Set the catid on the category to get only the fields which belong to
this category
			$item->catid = $item->id;
		}

		// Check the context
		$parts = FieldsHelper::extract($context, $item);

		if (!$parts)
		{
			return true;
		}

		// Compile the right context for the fields
		$context = $parts[0] . '.' . $parts[1];

		// Loading the fields
		$fields = FieldsHelper::getFields($context, $item);

		if (!$fields)
		{
			return true;
		}

		// Loading the model
		$model = JModelLegacy::getInstance('Field',
'FieldsModel', array('ignore_request' => true));

		// Loop over the fields
		foreach ($fields as $field)
		{
			// Determine the value if it is (un)available from the data
			if (key_exists($field->name, $data['com_fields']))
			{
				$value = $data['com_fields'][$field->name] === false ?
null : $data['com_fields'][$field->name];
			}
			// Field not available on form, use stored value
			else
			{
				$value = $field->rawvalue;
			}

			// If no value set (empty) remove value from database
			if (is_array($value) ? !count($value) : !strlen($value))
			{
				$value = null;
			}

			// JSON encode value for complex fields
			if (is_array($value) && (count($value, COUNT_NORMAL) !==
count($value, COUNT_RECURSIVE) || !count(array_filter(array_keys($value),
'is_numeric'))))
			{
				$value = json_encode($value);
			}

			// Setting the value for the field and the item
			$model->setFieldValue($field->id, $item->id, $value);
		}

		return true;
	}

	/**
	 * The save event.
	 *
	 * @param   array    $userData  The date
	 * @param   boolean  $isNew     Is new
	 * @param   boolean  $success   Is success
	 * @param   string   $msg       The message
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onUserAfterSave($userData, $isNew, $success, $msg)
	{
		// It is not possible to manipulate the user during save events
		// Check if data is valid or we are in a recursion
		if (!$userData['id'] || !$success)
		{
			return true;
		}

		$user = JFactory::getUser($userData['id']);

		$task =
JFactory::getApplication()->input->getCmd('task');

		// Skip fields save when we activate a user, because we will lose the
saved data
		if (in_array($task, array('activate', 'block',
'unblock')))
		{
			return true;
		}

		// Trigger the events with a real user
		$this->onContentAfterSave('com_users.user', $user, false,
$userData);

		return true;
	}

	/**
	 * The delete event.
	 *
	 * @param   string    $context  The context
	 * @param   stdClass  $item     The item
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterDelete($context, $item)
	{
		$parts = FieldsHelper::extract($context, $item);

		if (!$parts || empty($item->id))
		{
			return true;
		}

		$context = $parts[0] . '.' . $parts[1];

		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_fields/models', 'FieldsModel');

		$model = JModelLegacy::getInstance('Field',
'FieldsModel', array('ignore_request' => true));
		$model->cleanupValues($context, $item->id);

		return true;
	}

	/**
	 * The user delete event.
	 *
	 * @param   stdClass  $user    The context
	 * @param   boolean   $succes  Is success
	 * @param   string    $msg     The message
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onUserAfterDelete($user, $succes, $msg)
	{
		$item     = new stdClass;
		$item->id = $user['id'];

		return $this->onContentAfterDelete('com_users.user', $item);
	}

	/**
	 * The form event.
	 *
	 * @param   JForm     $form  The form
	 * @param   stdClass  $data  The data
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onContentPrepareForm(JForm $form, $data)
	{
		$context = $form->getName();

		// When a category is edited, the context is
com_categories.categorycom_content
		if (strpos($context, 'com_categories.category') === 0)
		{
			$context = str_replace('com_categories.category',
'', $context) . '.categories';

			// Set the catid on the category to get only the fields which belong to
this category
			if (is_array($data) && key_exists('id', $data))
			{
				$data['catid'] = $data['id'];
			}

			if (is_object($data) && isset($data->id))
			{
				$data->catid = $data->id;
			}
		}

		$parts = FieldsHelper::extract($context, $form);

		if (!$parts)
		{
			return true;
		}

		$input = JFactory::getApplication()->input;

		// If we are on the save command we need the actual data
		$jformData = $input->get('jform', array(),
'array');

		if ($jformData && !$data)
		{
			$data = $jformData;
		}

		if (is_array($data))
		{
			$data = (object) $data;
		}

		FieldsHelper::prepareForm($parts[0] . '.' . $parts[1], $form,
$data);

		return true;
	}

	/**
	 * The display event.
	 *
	 * @param   string    $context     The context
	 * @param   stdClass  $item        The item
	 * @param   Registry  $params      The params
	 * @param   integer   $limitstart  The start
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterTitle($context, $item, $params, $limitstart
= 0)
	{
		return $this->display($context, $item, $params, 1);
	}

	/**
	 * The display event.
	 *
	 * @param   string    $context     The context
	 * @param   stdClass  $item        The item
	 * @param   Registry  $params      The params
	 * @param   integer   $limitstart  The start
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	public function onContentBeforeDisplay($context, $item, $params,
$limitstart = 0)
	{
		return $this->display($context, $item, $params, 2);
	}

	/**
	 * The display event.
	 *
	 * @param   string    $context     The context
	 * @param   stdClass  $item        The item
	 * @param   Registry  $params      The params
	 * @param   integer   $limitstart  The start
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	public function onContentAfterDisplay($context, $item, $params,
$limitstart = 0)
	{
		return $this->display($context, $item, $params, 3);
	}

	/**
	 * Performs the display event.
	 *
	 * @param   string    $context      The context
	 * @param   stdClass  $item         The item
	 * @param   Registry  $params       The params
	 * @param   integer   $displayType  The type
	 *
	 * @return  string
	 *
	 * @since   3.7.0
	 */
	private function display($context, $item, $params, $displayType)
	{
		$parts = FieldsHelper::extract($context, $item);

		if (!$parts)
		{
			return '';
		}

		// If we have a category, set the catid field to fetch only the fields
which belong to it
		if ($parts[1] == 'categories' &&
!isset($item->catid))
		{
			$item->catid = $item->id;
		}

		$context = $parts[0] . '.' . $parts[1];

		// Convert tags
		if ($context == 'com_tags.tag' &&
!empty($item->type_alias))
		{
			// Set the context
			$context = $item->type_alias;

			$item = $this->prepareTagItem($item);
		}

		if (is_string($params) || !$params)
		{
			$params = new Registry($params);
		}

		$fields = FieldsHelper::getFields($context, $item, $displayType);

		if ($fields)
		{
			$app = Factory::getApplication();

			if ($app->isClient('site') &&
Multilanguage::isEnabled() && isset($item->language) &&
$item->language == '*')
			{
				$lang = $app->getLanguage()->getTag();

				foreach ($fields as $key => $field)
				{
					if ($field->language == '*' || $field->language ==
$lang)
					{
						continue;
					}

					unset($fields[$key]);
				}
			}
		}

		if ($fields)
		{
			foreach ($fields as $key => $field)
			{
				$fieldDisplayType = $field->params->get('display',
'2');

				if ($fieldDisplayType == $displayType)
				{
					continue;
				}

				unset($fields[$key]);
			}
		}

		if ($fields)
		{
			return FieldsHelper::render(
				$context,
				'fields.render',
				array(
					'item'            => $item,
					'context'         => $context,
					'fields'          => $fields
				)
			);
		}

		return '';
	}

	/**
	 * Performs the display event.
	 *
	 * @param   string    $context  The context
	 * @param   stdClass  $item     The item
	 *
	 * @return  void
	 *
	 * @since   3.7.0
	 */
	public function onContentPrepare($context, $item)
	{
		// Check property exists (avoid costly & useless recreation), if need
to recreate them, just unset the property!
		if (isset($item->jcfields))
		{
			return;
		}

		$parts = FieldsHelper::extract($context, $item);

		if (!$parts)
		{
			return;
		}

		$context = $parts[0] . '.' . $parts[1];

		// Convert tags
		if ($context == 'com_tags.tag' &&
!empty($item->type_alias))
		{
			// Set the context
			$context = $item->type_alias;

			$item = $this->prepareTagItem($item);
		}

		// Get item's fields, also preparing their value property for manual
display
		// (calling plugins events and loading layouts to get their HTML display)
		$fields = FieldsHelper::getFields($context, $item, true);

		// Adding the fields to the object
		$item->jcfields = array();

		foreach ($fields as $key => $field)
		{
			$item->jcfields[$field->id] = $field;
		}
	}

	/**
	 * The finder event.
	 *
	 * @param   stdClass  $item  The item
	 *
	 * @return  boolean
	 *
	 * @since   3.7.0
	 */
	public function onPrepareFinderContent($item)
	{
		$section = strtolower($item->layout);
		$tax     = $item->getTaxonomy('Type');

		if ($tax)
		{
			foreach ($tax as $context => $value)
			{
				// This is only a guess, needs to be improved
				$component = strtolower($context);

				if (strpos($context, 'com_') !== 0)
				{
					$component = 'com_' . $component;
				}

				// Transform com_article to com_content
				if ($component === 'com_article')
				{
					$component = 'com_content';
				}

				// Create a dummy object with the required fields
				$tmp     = new stdClass;
				$tmp->id = $item->__get('id');

				if ($item->__get('catid'))
				{
					$tmp->catid = $item->__get('catid');
				}

				// Getting the fields for the constructed context
				$fields = FieldsHelper::getFields($component . '.' .
$section, $tmp, true);

				if (is_array($fields))
				{
					foreach ($fields as $field)
					{
						// Adding the instructions how to handle the text
						$item->addInstruction(FinderIndexer::TEXT_CONTEXT,
$field->name);

						// Adding the field value as a field
						$item->{$field->name} = $field->value;
					}
				}
			}
		}

		return true;
	}

	/**
	 * Prepares a tag item to be ready for com_fields.
	 *
	 * @param   stdClass  $item  The item
	 *
	 * @return  object
	 *
	 * @since   3.8.4
	 */
	private function prepareTagItem($item)
	{
		// Map core fields
		$item->id       = $item->content_item_id;
		$item->language = $item->core_language;

		// Also handle the catid
		if (!empty($item->core_catid))
		{
			$item->catid = $item->core_catid;
		}

		return $item;
	}
}
system/fields/fields.xml000064400000001406147357022250011336
0ustar00<?xml version="1.0" encoding="utf-8" ?>
<extension type="plugin" version="3.7.0"
group="system" method="upgrade">
	<name>plg_system_fields</name>
	<author>Joomla! Project</author>
	<creationDate>March 2016</creationDate>
	<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.7.0</version>
	<description>PLG_SYSTEM_FIELDS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="fields">fields.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_fields.ini</language>
		<language
tag="en-GB">en-GB.plg_system_fields.sys.ini</language>
	</languages>
</extension>
system/highlight/highlight.php000064400000004074147357022250012533
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.Highlight
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * System plugin to highlight terms.
 *
 * @since  2.5
 */
class PlgSystemHighlight extends JPlugin
{
	/**
	 * Method to catch the onAfterDispatch event.
	 *
	 * This is where we setup the click-through content highlighting for.
	 * The highlighting is done with JavaScript so we just
	 * need to check a few parameters and the JHtml behavior will do the rest.
	 *
	 * @return  boolean  True on success
	 *
	 * @since   2.5
	 */
	public function onAfterDispatch()
	{
		// Check that we are in the site application.
		if (JFactory::getApplication()->isClient('administrator'))
		{
			return true;
		}

		// Set the variables.
		$input = JFactory::getApplication()->input;
		$extension = $input->get('option', '',
'cmd');

		// Check if the highlighter is enabled.
		if
(!JComponentHelper::getParams($extension)->get('highlight_terms',
1))
		{
			return true;
		}

		// Check if the highlighter should be activated in this environment.
		if ($input->get('tmpl', '', 'cmd') ===
'component' || JFactory::getDocument()->getType() !==
'html')
		{
			return true;
		}

		// Get the terms to highlight from the request.
		$terms = $input->request->get('highlight', null,
'base64');
		$terms = $terms ? json_decode(base64_decode($terms)) : null;

		// Check the terms.
		if (empty($terms))
		{
			return true;
		}

		// Clean the terms array.
		$filter     = JFilterInput::getInstance();

		$cleanTerms = array();

		foreach ($terms as $term)
		{
			$cleanTerms[] = htmlspecialchars($filter->clean($term,
'string'));
		}

		// Activate the highlighter.
		JHtml::_('behavior.highlighter', $cleanTerms);

		// Adjust the component buffer.
		$doc = JFactory::getDocument();
		$buf = $doc->getBuffer('component');
		$buf = '<br id="highlighter-start" />' . $buf .
'<br id="highlighter-end" />';
		$doc->setBuffer($buf, 'component');

		return true;
	}
}
system/highlight/highlight.xml000064400000001464147357022250012544
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_highlight</name>
	<author>Joomla! Project</author>
	<creationDate>August 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later;
see	LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_HIGHLIGHT_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="highlight">highlight.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">language/en-GB/en-GB.plg_system_highlight.ini</language>
		<language
tag="en-GB">language/en-GB/en-GB.plg_system_highlight.sys.ini</language>
	</languages>
</extension>
system/languagecode/language/en-GB/en-GB.plg_system_languagecode.ini000064400000001641147357022250021446
0ustar00; Joomla! Project
; (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8

PLG_SYSTEM_LANGUAGECODE="System - Language Code"
PLG_SYSTEM_LANGUAGECODE_FIELD_DESC="Changes the language code used for
the <em>%s</em> language."
PLG_SYSTEM_LANGUAGECODE_FIELDSET_DESC="Changes the language code for
the generated HTML document. Example usage: You have installed the fr-FR
language pack and want the Search Engines to recognise the page as aimed at
French-speaking Canada. Add the tag 'fr-CA' to the corresponding
field for 'fr-FR' to resolve this."
PLG_SYSTEM_LANGUAGECODE_FIELDSET_LABEL="Language codes"
PLG_SYSTEM_LANGUAGECODE_XML_DESCRIPTION="Provides the ability to
change the language code in the generated HTML document to improve
SEO.<br />The fields will appear when the plugin is enabled and
saved."
system/languagecode/language/en-GB/en-GB.plg_system_languagecode.sys.ini000064400000000602147357022250022257
0ustar00; Joomla! Project
; (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
; License GNU General Public License version 2 or later; see LICENSE.txt
; Note : All ini files need to be saved as UTF-8

PLG_SYSTEM_LANGUAGECODE="System - Language Code"
PLG_SYSTEM_LANGUAGECODE_XML_DESCRIPTION="Provides ability to change
the language code in the generated HTML document to improve SEO"

system/languagecode/languagecode.php000064400000010013147357022250013637
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.languagecode
 *
 * @copyright   (C) 2011 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Language Code plugin class.
 *
 * @since  2.5
 */
class PlgSystemLanguagecode extends JPlugin
{
	/**
	 * Plugin that changes the language code used in the <html /> tag.
	 *
	 * @return  void
	 *
	 * @since   2.5
	 */
	public function onAfterRender()
	{
		$app = JFactory::getApplication();

		// Use this plugin only in site application.
		if ($app->isClient('site'))
		{
			// Get the response body.
			$body = $app->getBody();

			// Get the current language code.
			$code = JFactory::getDocument()->getLanguage();

			// Get the new code.
			$new_code  = $this->params->get($code);

			// Replace the old code by the new code in the <html /> tag.
			if ($new_code)
			{
				// Replace the new code in the HTML document.
				$patterns = array(
					chr(1) . '(<html.*\s+xml:lang=")(' . $code .
')(".*>)' . chr(1) . 'i',
					chr(1) . '(<html.*\s+lang=")(' . $code .
')(".*>)' . chr(1) . 'i',
				);
				$replace = array(
					'${1}' . strtolower($new_code) . '${3}',
					'${1}' . strtolower($new_code) . '${3}'
				);
			}
			else
			{
				$patterns = array();
				$replace  = array();
			}

			// Replace codes in <link hreflang="" /> attributes.
			preg_match_all(chr(1) .
'(<link.*\s+hreflang=")([0-9a-z\-]*)(".*\s+rel="alternate".*/>)'
. chr(1) . 'i', $body, $matches);

			foreach ($matches[2] as $match)
			{
				$new_code = $this->params->get(strtolower($match));

				if ($new_code)
				{
					$patterns[] = chr(1) . '(<link.*\s+hreflang=")(' .
$match . ')(".*\s+rel="alternate".*/>)' .
chr(1) . 'i';
					$replace[] = '${1}' . $new_code . '${3}';
				}
			}

			preg_match_all(chr(1) .
'(<link.*\s+rel="alternate".*\s+hreflang=")([0-9A-Za-z\-]*)(".*/>)'
. chr(1) . 'i', $body, $matches);

			foreach ($matches[2] as $match)
			{
				$new_code = $this->params->get(strtolower($match));

				if ($new_code)
				{
					$patterns[] = chr(1) .
'(<link.*\s+rel="alternate".*\s+hreflang=")(' .
$match . ')(".*/>)' . chr(1) . 'i';
					$replace[] = '${1}' . $new_code . '${3}';
				}
			}

			// Replace codes in itemprop content
			preg_match_all(chr(1) .
'(<meta.*\s+itemprop="inLanguage".*\s+content=")([0-9A-Za-z\-]*)(".*/>)'
. chr(1) . 'i', $body, $matches);

			foreach ($matches[2] as $match)
			{
				$new_code = $this->params->get(strtolower($match));

				if ($new_code)
				{
					$patterns[] = chr(1) .
'(<meta.*\s+itemprop="inLanguage".*\s+content=")('
. $match . ')(".*/>)' . chr(1) . 'i';
					$replace[] = '${1}' . $new_code . '${3}';
				}
			}

			$app->setBody(preg_replace($patterns, $replace, $body));
		}
	}

	/**
	 * Prepare form.
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since	2.5
	 */
	public function onContentPrepareForm(JForm $form, $data)
	{
		// Check we are manipulating the languagecode plugin.
		if ($form->getName() !== 'com_plugins.plugin' ||
!$form->getField('languagecodeplugin', 'params'))
		{
			return true;
		}

		// Get site languages.
		if ($languages = JLanguageHelper::getKnownLanguages(JPATH_SITE))
		{
			// Inject fields into the form.
			foreach ($languages as $tag => $language)
			{
				$form->load('
					<form>
						<fields name="params">
							<fieldset
								name="languagecode"
								label="PLG_SYSTEM_LANGUAGECODE_FIELDSET_LABEL"
								description="PLG_SYSTEM_LANGUAGECODE_FIELDSET_DESC"
							>
								<field
									name="' . strtolower($tag) . '"
									type="text"
									label="' . $tag . '"
									description="' .
htmlspecialchars(JText::sprintf('PLG_SYSTEM_LANGUAGECODE_FIELD_DESC',
$language['name']), ENT_COMPAT, 'UTF-8') . '"
									translate_description="false"
									translate_label="false"
									size="7"
									filter="cmd"
								/>
							</fieldset>
						</fields>
					</form>
				');
			}
		}

		return true;
	}
}
system/languagecode/languagecode.xml000064400000001761147357022250013662
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_languagecode</name>
	<author>Joomla! Project</author>
	<creationDate>November 2011</creationDate>
	<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_LANGUAGECODE_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="languagecode">languagecode.php</filename>
		<folder>language</folder>
	</files>
	<languages>
		<language
tag="en-GB">language/en-GB/en-GB.plg_system_languagecode.ini</language>
		<language
tag="en-GB">language/en-GB/en-GB.plg_system_languagecode.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<field
				name="languagecodeplugin"
				type="hidden"
				default="true"
			/>
		</fields>
	</config>
</extension>
system/languagefilter/languagefilter.php000064400000061215147357022250014577
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.languagefilter
 *
 * @copyright   (C) 2010 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;
use Joomla\String\StringHelper;

JLoader::register('MenusHelper', JPATH_ADMINISTRATOR .
'/components/com_menus/helpers/menus.php');

/**
 * Joomla! Language Filter Plugin.
 *
 * @since  1.6
 */
class PlgSystemLanguageFilter extends JPlugin
{
	/**
	 * The routing mode.
	 *
	 * @var    boolean
	 * @since  2.5
	 */
	protected $mode_sef;

	/**
	 * Available languages by sef.
	 *
	 * @var    array
	 * @since  1.6
	 */
	protected $sefs;

	/**
	 * Available languages by language codes.
	 *
	 * @var    array
	 * @since  2.5
	 */
	protected $lang_codes;

	/**
	 * The current language code.
	 *
	 * @var    string
	 * @since  3.4.2
	 */
	protected $current_lang;

	/**
	 * The default language code.
	 *
	 * @var    string
	 * @since  2.5
	 */
	protected $default_lang;

	/**
	 * The logged user language code.
	 *
	 * @var    string
	 * @since  3.3.1
	 */
	private $user_lang_code;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.3
	 */
	protected $app;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An optional associative array of
configuration settings.
	 *
	 * @since   1.6
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		$this->app = JFactory::getApplication();

		// Setup language data.
		$this->mode_sef     = $this->app->get('sef', 0);
		$this->sefs         = JLanguageHelper::getLanguages('sef');
		$this->lang_codes   =
JLanguageHelper::getLanguages('lang_code');
		$this->default_lang =
JComponentHelper::getParams('com_languages')->get('site',
'en-GB');

		// If language filter plugin is executed in a site page.
		if ($this->app->isClient('site'))
		{
			$levels = JFactory::getUser()->getAuthorisedViewLevels();

			foreach ($this->sefs as $sef => $language)
			{
				// @todo: In Joomla 2.5.4 and earlier access wasn't set. Non
modified Content Languages got 0 as access value
				// we also check if frontend language exists and is enabled
				if (($language->access && !in_array($language->access,
$levels))
					|| (!array_key_exists($language->lang_code,
JLanguageHelper::getInstalledLanguages(0))))
				{
					unset($this->lang_codes[$language->lang_code],
$this->sefs[$language->sef]);
				}
			}
		}
		// If language filter plugin is executed in an admin page (ex: JRoute
site).
		else
		{
			// Set current language to default site language, fallback to en-GB if
there is no content language for the default site language.
			$this->current_lang =
isset($this->lang_codes[$this->default_lang]) ?
$this->default_lang : 'en-GB';

			foreach ($this->sefs as $sef => $language)
			{
				if (!array_key_exists($language->lang_code,
JLanguageHelper::getInstalledLanguages(0)))
				{
					unset($this->lang_codes[$language->lang_code]);
					unset($this->sefs[$language->sef]);
				}
			}
		}
	}

	/**
	 * After initialise.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onAfterInitialise()
	{
		$this->app->item_associations =
$this->params->get('item_associations', 0);

		// We need to make sure we are always using the site router, even if the
language plugin is executed in admin app.
		$router =
JApplicationCms::getInstance('site')->getRouter('site');

		// Attach build rules for language SEF.
		$router->attachBuildRule(array($this,
'preprocessBuildRule'), JRouter::PROCESS_BEFORE);
		$router->attachBuildRule(array($this, 'buildRule'),
JRouter::PROCESS_DURING);

		if ($this->mode_sef)
		{
			$router->attachBuildRule(array($this,
'postprocessSEFBuildRule'), JRouter::PROCESS_AFTER);
		}
		else
		{
			$router->attachBuildRule(array($this,
'postprocessNonSEFBuildRule'), JRouter::PROCESS_AFTER);
		}

		// Attach parse rules for language SEF.
		$router->attachParseRule(array($this, 'parseRule'),
JRouter::PROCESS_DURING);
	}

	/**
	 * After route.
	 *
	 * @return  void
	 *
	 * @since   3.4
	 */
	public function onAfterRoute()
	{
		// Add custom site name.
		if ($this->app->isClient('site') &&
isset($this->lang_codes[$this->current_lang]) &&
$this->lang_codes[$this->current_lang]->sitename)
		{
			$this->app->set('sitename',
$this->lang_codes[$this->current_lang]->sitename);
		}
	}

	/**
	 * Add build preprocess rule to router.
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   3.4
	 */
	public function preprocessBuildRule(&$router, &$uri)
	{
		$lang = $uri->getVar('lang', $this->current_lang);
		$uri->setVar('lang', $lang);

		if (isset($this->sefs[$lang]))
		{
			$lang = $this->sefs[$lang]->lang_code;
			$uri->setVar('lang', $lang);
		}
	}

	/**
	 * Add build rule to router.
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function buildRule(&$router, &$uri)
	{
		$lang = $uri->getVar('lang');

		if (isset($this->lang_codes[$lang]))
		{
			$sef = $this->lang_codes[$lang]->sef;
		}
		else
		{
			$sef = $this->lang_codes[$this->current_lang]->sef;
		}

		if ($this->mode_sef
			&& (!$this->params->get('remove_default_prefix',
0)
			|| $lang !== $this->default_lang
			|| $lang !== $this->current_lang))
		{
			$uri->setPath($uri->getPath() . '/' . $sef .
'/');
		}
	}

	/**
	 * postprocess build rule for SEF URLs
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   3.4
	 */
	public function postprocessSEFBuildRule(&$router, &$uri)
	{
		$uri->delVar('lang');
	}

	/**
	 * postprocess build rule for non-SEF URLs
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   3.4
	 */
	public function postprocessNonSEFBuildRule(&$router, &$uri)
	{
		$lang = $uri->getVar('lang');

		if (isset($this->lang_codes[$lang]))
		{
			$uri->setVar('lang', $this->lang_codes[$lang]->sef);
		}
	}

	/**
	 * Add parse rule to router.
	 *
	 * @param   JRouter  &$router  JRouter object.
	 * @param   JUri     &$uri     JUri object.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function parseRule(&$router, &$uri)
	{
		// Did we find the current and existing language yet?
		$found = false;

		// Are we in SEF mode or not?
		if ($this->mode_sef)
		{
			$path = $uri->getPath();
			$parts = explode('/', $path);

			$sef = StringHelper::strtolower($parts[0]);

			// Do we have a URL Language Code ?
			if (!isset($this->sefs[$sef]))
			{
				// Check if remove default URL language code is set
				if ($this->params->get('remove_default_prefix', 0))
				{
					if ($parts[0])
					{
						// We load a default site language page
						$lang_code = $this->default_lang;
					}
					else
					{
						// We check for an existing language cookie
						$lang_code = $this->getLanguageCookie();
					}
				}
				else
				{
					$lang_code = $this->getLanguageCookie();
				}

				// No language code. Try using browser settings or default site
language
				if (!$lang_code &&
$this->params->get('detect_browser', 0) == 1)
				{
					$lang_code = JLanguageHelper::detectLanguage();
				}

				if (!$lang_code)
				{
					$lang_code = $this->default_lang;
				}

				if ($lang_code === $this->default_lang &&
$this->params->get('remove_default_prefix', 0))
				{
					$found = true;
				}
			}
			else
			{
				// We found our language
				$found = true;
				$lang_code = $this->sefs[$sef]->lang_code;

				// If we found our language, but its the default language and we
don't want a prefix for that, we are on a wrong URL.
				// Or we try to change the language back to the default language. We
need a redirect to the proper URL for the default language.
				if ($lang_code === $this->default_lang &&
$this->params->get('remove_default_prefix', 0))
				{
					// Create a cookie.
					$this->setLanguageCookie($lang_code);

					$found = false;
					array_shift($parts);
					$path = implode('/', $parts);
				}

				// We have found our language and the first part of our URL is the
language prefix
				if ($found)
				{
					array_shift($parts);

					// Empty parts array when "index.php" is the only part left.
					if (count($parts) === 1 && $parts[0] ===
'index.php')
					{
						$parts = array();
					}

					$uri->setPath(implode('/', $parts));
				}
			}
		}
		// We are not in SEF mode
		else
		{
			$lang_code = $this->getLanguageCookie();

			if (!$lang_code &&
$this->params->get('detect_browser', 1))
			{
				$lang_code = JLanguageHelper::detectLanguage();
			}

			if (!isset($this->lang_codes[$lang_code]))
			{
				$lang_code = $this->default_lang;
			}
		}

		$lang = $uri->getVar('lang', $lang_code);

		if (isset($this->sefs[$lang]))
		{
			// We found our language
			$found = true;
			$lang_code = $this->sefs[$lang]->lang_code;
		}

		// We are called via POST or the nolangfilter url parameter was set. We
don't care about the language
		// and simply set the default language as our current language.
		if ($this->app->input->getMethod() === 'POST'
			|| $this->app->input->get('nolangfilter', 0) == 1
			|| count($this->app->input->post) > 0
			|| count($this->app->input->files) > 0)
		{
			$found = true;

			if (!isset($lang_code))
			{
				$lang_code = $this->getLanguageCookie();
			}

			if (!$lang_code &&
$this->params->get('detect_browser', 1))
			{
				$lang_code = JLanguageHelper::detectLanguage();
			}

			if (!isset($this->lang_codes[$lang_code]))
			{
				$lang_code = $this->default_lang;
			}
		}

		// We have not found the language and thus need to redirect
		if (!$found)
		{
			// Lets find the default language for this user
			if (!isset($lang_code) || !isset($this->lang_codes[$lang_code]))
			{
				$lang_code = false;

				if ($this->params->get('detect_browser', 1))
				{
					$lang_code = JLanguageHelper::detectLanguage();

					if (!isset($this->lang_codes[$lang_code]))
					{
						$lang_code = false;
					}
				}

				if (!$lang_code)
				{
					$lang_code = $this->default_lang;
				}
			}

			if ($this->mode_sef)
			{
				// Use the current language sef or the default one.
				if ($lang_code !== $this->default_lang
					|| !$this->params->get('remove_default_prefix', 0))
				{
					$path = $this->lang_codes[$lang_code]->sef . '/' .
$path;
				}

				$uri->setPath($path);

				if (!$this->app->get('sef_rewrite'))
				{
					$uri->setPath('index.php/' . $uri->getPath());
				}

				$redirectUri = $uri->base() .
$uri->toString(array('path', 'query',
'fragment'));
			}
			else
			{
				$uri->setVar('lang',
$this->lang_codes[$lang_code]->sef);
				$redirectUri = $uri->base() . 'index.php?' .
$uri->getQuery();
			}

			// Set redirect HTTP code to "302 Found".
			$redirectHttpCode = 302;

			// If selected language is the default language redirect code is
"301 Moved Permanently".
			if ($lang_code === $this->default_lang)
			{
				$redirectHttpCode = 301;

				// We cannot cache this redirect in browser. 301 is cachable by default
so we need to force to not cache it in browsers.
				$this->app->setHeader('Expires', 'Wed, 17 Aug 2005
00:00:00 GMT', true);
				$this->app->setHeader('Last-Modified', gmdate('D,
d M Y H:i:s') . ' GMT', true);
				$this->app->setHeader('Cache-Control', 'no-store,
no-cache, must-revalidate, post-check=0, pre-check=0', false);
				$this->app->setHeader('Pragma', 'no-cache');
				$this->app->sendHeaders();
			}

			// Redirect to language.
			$this->app->redirect($redirectUri, $redirectHttpCode);
		}

		// We have found our language and now need to set the cookie and the
language value in our system
		$array = array('lang' => $lang_code);
		$this->current_lang = $lang_code;

		// Set the request var.
		$this->app->input->set('language', $lang_code);
		$this->app->set('language', $lang_code);
		$language = JFactory::getLanguage();

		if ($language->getTag() !== $lang_code)
		{
			$language_new = JLanguage::getInstance($lang_code, (bool)
$this->app->get('debug_lang'));

			foreach ($language->getPaths() as $extension => $files)
			{
				if (strpos($extension, 'plg_system') !== false)
				{
					$extension_name = substr($extension, 11);

					$language_new->load($extension, JPATH_ADMINISTRATOR)
					|| $language_new->load($extension, JPATH_PLUGINS .
'/system/' . $extension_name);

					continue;
				}

				$language_new->load($extension);
			}

			JFactory::$language = $language_new;
			$this->app->loadLanguage($language_new);
		}

		// Create a cookie.
		if ($this->getLanguageCookie() !== $lang_code)
		{
			$this->setLanguageCookie($lang_code);
		}

		return $array;
	}

	/**
	 * Reports the privacy related capabilities for this plugin to site
administrators.
	 *
	 * @return  array
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCollectAdminCapabilities()
	{
		$this->loadLanguage();

		return array(
			JText::_('PLG_SYSTEM_LANGUAGEFILTER') => array(
				JText::_('PLG_SYSTEM_LANGUAGEFILTER_PRIVACY_CAPABILITY_LANGUAGE_COOKIE'),
			)
		);
	}

	/**
	 * Before store user method.
	 *
	 * Method is called before user data is stored in the database.
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isnew  True if a new user is stored.
	 * @param   array    $new    Holds the new user data.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onUserBeforeSave($user, $isnew, $new)
	{
		if (array_key_exists('params', $user) &&
$this->params->get('automatic_change', 1) == 1)
		{
			$registry = new Registry($user['params']);
			$this->user_lang_code = $registry->get('language');

			if (empty($this->user_lang_code))
			{
				$this->user_lang_code = $this->current_lang;
			}
		}
	}

	/**
	 * After store user method.
	 *
	 * Method is called after user data is stored in the database.
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isnew    True if a new user is stored.
	 * @param   boolean  $success  True if user was succesfully stored in the
database.
	 * @param   string   $msg      Message.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		if ($success && array_key_exists('params', $user)
&& $this->params->get('automatic_change', 1) == 1)
		{
			$registry = new Registry($user['params']);
			$lang_code = $registry->get('language');

			if (empty($lang_code))
			{
				$lang_code = $this->current_lang;
			}

			if ($lang_code === $this->user_lang_code ||
!isset($this->lang_codes[$lang_code]))
			{
				if ($this->app->isClient('site'))
				{
					$this->app->setUserState('com_users.edit.profile.redirect',
null);
				}
			}
			else
			{
				if ($this->app->isClient('site'))
				{
					$this->app->setUserState('com_users.edit.profile.redirect',
'index.php?Itemid='
						. $this->app->getMenu()->getDefault($lang_code)->id .
'&lang=' . $this->lang_codes[$lang_code]->sef
					);

					// Create a cookie.
					$this->setLanguageCookie($lang_code);
				}
			}
		}
	}

	/**
	 * Method to handle any login logic and report back to the subject.
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (remember,
autoregister, group).
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   1.5
	 */
	public function onUserLogin($user, $options = array())
	{
		$menu = $this->app->getMenu();

		if ($this->app->isClient('site'))
		{
			if ($this->params->get('automatic_change', 1))
			{
				$assoc = JLanguageAssociations::isEnabled();
				$lang_code = $user['language'];

				// If no language is specified for this user, we set it to the site
default language
				if (empty($lang_code))
				{
					$lang_code = $this->default_lang;
				}

				jimport('joomla.filesystem.folder');

				// The language has been deleted/disabled or the related content
language does not exist/has been unpublished
				// or the related home page does not exist/has been unpublished
				if (!array_key_exists($lang_code, $this->lang_codes)
					|| !array_key_exists($lang_code,
JLanguageMultilang::getSiteHomePages())
					|| !JFolder::exists(JPATH_SITE . '/language/' . $lang_code))
				{
					$lang_code = $this->current_lang;
				}

				// Try to get association from the current active menu item
				$active = $menu->getActive();

				$foundAssociation = false;

				/**
				 * Looking for associations.
				 * If the login menu item form contains an internal URL redirection,
				 * This will override the automatic change to the user preferred site
language.
				 * In that case we use the redirect as defined in the menu item.
				 *  Otherwise we redirect, when available, to the user preferred site
language.
				 */
				if ($active &&
!$active->params['login_redirect_url'])
				{
					if ($assoc)
					{
						$associations = MenusHelper::getAssociations($active->id);
					}

					// Retrieves the Itemid from a login form.
					$uri = new
JUri($this->app->getUserState('users.login.form.return'));

					if ($uri->getVar('Itemid'))
					{
						// The login form contains a menu item redirection. Try to get
associations from that menu item.
						// If any association set to the user preferred site language,
redirect to that page.
						if ($assoc)
						{
							$associations =
MenusHelper::getAssociations($uri->getVar('Itemid'));
						}

						if (isset($associations[$lang_code]) &&
$menu->getItem($associations[$lang_code]))
						{
							$associationItemid = $associations[$lang_code];
							$this->app->setUserState('users.login.form.return',
'index.php?Itemid=' . $associationItemid);
							$foundAssociation = true;
						}
					}
					elseif (isset($associations[$lang_code]) &&
$menu->getItem($associations[$lang_code]))
					{
						/**
						 * The login form does not contain a menu item redirection.
						 * The active menu item has associations.
						 * We redirect to the user preferred site language associated page.
						 */
						$associationItemid = $associations[$lang_code];
						$this->app->setUserState('users.login.form.return',
'index.php?Itemid=' . $associationItemid);
						$foundAssociation = true;
					}
					elseif ($active->home)
					{
						// We are on a Home page, we redirect to the user preferred site
language Home page.
						$item = $menu->getDefault($lang_code);

						if ($item && $item->language !== $active->language
&& $item->language !== '*')
						{
							$this->app->setUserState('users.login.form.return',
'index.php?Itemid=' . $item->id);
							$foundAssociation = true;
						}
					}
				}

				if ($foundAssociation && $lang_code !== $this->current_lang)
				{
					// Change language.
					$this->current_lang = $lang_code;

					// Create a cookie.
					$this->setLanguageCookie($lang_code);

					// Change the language code.
					JFactory::getLanguage()->setLanguage($lang_code);
				}
			}
			else
			{
				if
($this->app->getUserState('users.login.form.return'))
				{
					$this->app->setUserState('users.login.form.return',
JRoute::_($this->app->getUserState('users.login.form.return'),
false));
				}
			}
		}
	}

	/**
	 * Method to add alternative meta tags for associated menu items.
	 *
	 * @return  void
	 *
	 * @since   1.7
	 */
	public function onAfterDispatch()
	{
		$doc = JFactory::getDocument();

		if ($this->app->isClient('site') &&
$this->params->get('alternate_meta', 1) &&
$doc->getType() === 'html')
		{
			$languages             = $this->lang_codes;
			$homes                 = JLanguageMultilang::getSiteHomePages();
			$menu                  = $this->app->getMenu();
			$active                = $menu->getActive();
			$levels                =
JFactory::getUser()->getAuthorisedViewLevels();
			$remove_default_prefix =
$this->params->get('remove_default_prefix', 0);
			$server                =
JUri::getInstance()->toString(array('scheme',
'host', 'port'));
			$is_home               = false;
			$currentInternalUrl    = 'index.php?' .
http_build_query($this->app->getRouter()->getVars());

			if ($active)
			{
				$active_link  = JRoute::_($active->link . '&Itemid=' .
$active->id);
				$current_link = JRoute::_($currentInternalUrl);

				// Load menu associations
				if ($active_link === $current_link)
				{
					$associations = MenusHelper::getAssociations($active->id);
				}

				// Check if we are on the home page
				$is_home = ($active->home
					&& ($active_link === $current_link || $active_link ===
$current_link . 'index.php' || $active_link . '/' ===
$current_link));
			}

			// Load component associations.
			$option = $this->app->input->get('option');
			$cName = ucfirst(substr($option, 4)) . 'HelperAssociation';
			JLoader::register($cName, JPath::clean(JPATH_SITE .
'/components/' . $option .
'/helpers/association.php'));

			if (class_exists($cName) && is_callable(array($cName,
'getAssociations')))
			{
				$cassociations = call_user_func(array($cName,
'getAssociations'));
			}

			// For each language...
			foreach ($languages as $i => $language)
			{
				switch (true)
				{
					// Language without frontend UI || Language without specific home menu
|| Language without authorized access level
					case (!array_key_exists($i,
JLanguageHelper::getInstalledLanguages(0))):
					case (!isset($homes[$i])):
					case (isset($language->access) && $language->access
&& !in_array($language->access, $levels)):
						unset($languages[$i]);
						break;

					// Home page
					case ($is_home):
						$language->link = JRoute::_('index.php?lang=' .
$language->sef . '&Itemid=' . $homes[$i]->id);
						break;

					// Current language link
					case ($i === $this->current_lang):
						$language->link = JRoute::_($currentInternalUrl);
						break;

					// Component association
					case (isset($cassociations[$i])):
						$language->link = JRoute::_($cassociations[$i] .
'&lang=' . $language->sef);
						break;

					// Menu items association
					// Heads up! "$item = $menu" here below is an assignment,
*NOT* comparison
					case (isset($associations[$i]) && ($item =
$menu->getItem($associations[$i]))):

						$language->link = JRoute::_('index.php?Itemid=' .
$item->id . '&lang=' . $language->sef);
						break;

					// Too bad...
					default:
						unset($languages[$i]);
				}
			}

			// If there are at least 2 of them, add the rel="alternate"
links to the <head>
			if (count($languages) > 1)
			{
				// Remove the sef from the default language if "Remove URL
Language Code" is on
				if ($remove_default_prefix &&
isset($languages[$this->default_lang]))
				{
					$languages[$this->default_lang]->link
									= preg_replace('|/' .
$languages[$this->default_lang]->sef . '/|', '/',
$languages[$this->default_lang]->link, 1);
				}

				foreach ($languages as $i => $language)
				{
					$doc->addHeadLink($server . $language->link,
'alternate', 'rel', array('hreflang' =>
$i));
				}

				// Add x-default language tag
				if ($this->params->get('xdefault', 1))
				{
					$xdefault_language =
$this->params->get('xdefault_language',
$this->default_lang);
					$xdefault_language = ($xdefault_language === 'default') ?
$this->default_lang : $xdefault_language;

					if (isset($languages[$xdefault_language]))
					{
						// Use a custom tag because addHeadLink is limited to one URI per tag
						$doc->addCustomTag('<link href="' . $server .
$languages[$xdefault_language]->link . '"
rel="alternate" hreflang="x-default" />');
					}
				}
			}
		}
	}

	/**
	 * Set the language cookie
	 *
	 * @param   string  $languageCode  The language code for which we want to
set the cookie
	 *
	 * @return  void
	 *
	 * @since   3.4.2
	 */
	private function setLanguageCookie($languageCode)
	{
		// If is set to use language cookie for a year in plugin params, save the
user language in a new cookie.
		if ((int) $this->params->get('lang_cookie', 0) === 1)
		{
			// Create a cookie with one year lifetime.
			$this->app->input->cookie->set(
				JApplicationHelper::getHash('language'),
				$languageCode,
				time() + 365 * 86400,
				$this->app->get('cookie_path', '/'),
				$this->app->get('cookie_domain', ''),
				$this->app->isHttpsForced(),
				true
			);
		}
		// If not, set the user language in the session (that is already saved in
a cookie).
		else
		{
			JFactory::getSession()->set('plg_system_languagefilter.language',
$languageCode);
		}
	}

	/**
	 * Get the language cookie
	 *
	 * @return  string
	 *
	 * @since   3.4.2
	 */
	private function getLanguageCookie()
	{
		// Is is set to use a year language cookie in plugin params, get the user
language from the cookie.
		if ((int) $this->params->get('lang_cookie', 0) === 1)
		{
			$languageCode =
$this->app->input->cookie->get(JApplicationHelper::getHash('language'));
		}
		// Else get the user language from the session.
		else
		{
			$languageCode =
JFactory::getSession()->get('plg_system_languagefilter.language');
		}

		// Let's be sure we got a valid language code. Fallback to null.
		if (!array_key_exists($languageCode, $this->lang_codes))
		{
			$languageCode = null;
		}

		return $languageCode;
	}
}
system/languagefilter/languagefilter.xml000064400000007563147357022250014616
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_languagefilter</name>
	<author>Joomla! Project</author>
	<creationDate>July 2010</creationDate>
	<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_LANGUAGEFILTER_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="languagefilter">languagefilter.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_languagefilter.ini</language>
		<language
tag="en-GB">en-GB.plg_system_languagefilter.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="detect_browser"
					type="list"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_DETECT_BROWSER_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_DETECT_BROWSER_DESC"
					default="0"
					filter="integer"
					>
					<option
value="0">PLG_SYSTEM_LANGUAGEFILTER_SITE_LANGUAGE</option>
					<option
value="1">PLG_SYSTEM_LANGUAGEFILTER_BROWSER_SETTINGS</option>
				</field>

				<field
					name="automatic_change"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_AUTOMATIC_CHANGE_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_AUTOMATIC_CHANGE_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="item_associations"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ITEM_ASSOCIATIONS_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ITEM_ASSOCIATIONS_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="alternate_meta"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ALTERNATE_META_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ALTERNATE_META_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="xdefault"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					showon="alternate_meta:1"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="xdefault_language"
					type="contentlanguage"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LANGUAGE_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LANGUAGE_DESC"
					default="default"
					showon="alternate_meta:1[AND]xdefault:1"
					>
					<option
value="default">PLG_SYSTEM_LANGUAGEFILTER_OPTION_DEFAULT_LANGUAGE</option>
				</field>

				<field
					name="remove_default_prefix"
					type="radio"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_REMOVE_DEFAULT_PREFIX_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_REMOVE_DEFAULT_PREFIX_DESC"
					default="0"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="lang_cookie"
					type="list"
					label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_COOKIE_LABEL"
					description="PLG_SYSTEM_LANGUAGEFILTER_FIELD_COOKIE_DESC"
					default="0"
					filter="integer"
					>
					<option
value="1">PLG_SYSTEM_LANGUAGEFILTER_OPTION_YEAR</option>
					<option
value="0">PLG_SYSTEM_LANGUAGEFILTER_OPTION_SESSION</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>system/log/log.php000064400000003010147357022250010144
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.log
 *
 * @copyright   (C) 2007 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! System Logging Plugin.
 *
 * @since  1.5
 */
class PlgSystemLog extends JPlugin
{
	/**
	 * Called if user fails to be logged in.
	 *
	 * @param   array  $response  Array of response data.
	 *
	 * @return  void
	 *
	 * @since   1.5
	 */
	public function onUserLoginFailure($response)
	{
		$errorlog = array();

		switch ($response['status'])
		{
			case JAuthentication::STATUS_SUCCESS:
				$errorlog['status']  = $response['type'] . '
CANCELED: ';
				$errorlog['comment'] = $response['error_message'];
				break;

			case JAuthentication::STATUS_FAILURE:
				$errorlog['status']  = $response['type'] . '
FAILURE: ';

				if ($this->params->get('log_username', 0))
				{
					$errorlog['comment'] = $response['error_message']
. ' ("' . $response['username'] .
'")';
				}
				else
				{
					$errorlog['comment'] = $response['error_message'];
				}
				break;

			default:
				$errorlog['status']  = $response['type'] . '
UNKNOWN ERROR: ';
				$errorlog['comment'] = $response['error_message'];
				break;
		}

		JLog::addLogger(array(), JLog::INFO);

		try
		{
			JLog::add($errorlog['comment'], JLog::INFO,
$errorlog['status']);
		}
		catch (Exception $e)
		{
			// If the log file is unwriteable during login then we should not go to
the error page
			return;
		}
	}
}
system/log/log.xml000064400000002236147357022250010166 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_log</name>
	<author>Joomla! Project</author>
	<creationDate>April 2007</creationDate>
	<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_LOG_XML_DESCRIPTION</description>
	<files>
		<filename plugin="log">log.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_log.ini</language>
		<language
tag="en-GB">en-GB.plg_system_log.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="log_username"
					type="radio"
					label="PLG_SYSTEM_LOG_FIELD_LOG_USERNAME_LABEL"
					description="PLG_SYSTEM_LOG_FIELD_LOG_USERNAME_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
system/logout/logout.php000064400000005302147357022250011432
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.logout
 *
 * @copyright   (C) 2010 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Plugin class for logout redirect handling.
 *
 * @since  1.6
 */
class PlgSystemLogout extends JPlugin
{
	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.7.3
	 */
	protected $app;

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe -- event
dispatcher.
	 * @param   object  $config    An optional associative array of
configuration settings.
	 *
	 * @since   1.6
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		// If we are on admin don't process.
		if (!$this->app->isClient('site'))
		{
			return;
		}

		$hash  = JApplicationHelper::getHash('PlgSystemLogout');

		if ($this->app->input->cookie->getString($hash))
		{
			// Destroy the cookie.
			$this->app->input->cookie->set($hash, '', 1,
$this->app->get('cookie_path', '/'),
$this->app->get('cookie_domain', ''));

			// Set the error handler for E_ALL to be the class handleError method.
			JError::setErrorHandling(E_ALL, 'callback',
array('PlgSystemLogout', 'handleError'));
		}
	}

	/**
	 * Method to handle any logout logic and report back to the subject.
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (client, ...).
	 *
	 * @return  boolean  Always returns true.
	 *
	 * @since   1.6
	 */
	public function onUserLogout($user, $options = array())
	{
		if ($this->app->isClient('site'))
		{
			// Create the cookie.
			$this->app->input->cookie->set(
				JApplicationHelper::getHash('PlgSystemLogout'),
				true,
				time() + 86400,
				$this->app->get('cookie_path', '/'),
				$this->app->get('cookie_domain', ''),
				$this->app->isHttpsForced(),
				true
			);
		}

		return true;
	}

	/**
	 * Method to handle an error condition.
	 *
	 * @param   Exception  &$error  The Exception object to be handled.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public static function handleError(&$error)
	{
		// Get the application object.
		$app = JFactory::getApplication();

		// Make sure the error is a 403 and we are in the frontend.
		if ($error->getCode() == 403 &&
$app->isClient('site'))
		{
			// Redirect to the home page.
			$app->enqueueMessage(JText::_('PLG_SYSTEM_LOGOUT_REDIRECT'));
			$app->redirect('index.php');
		}
		else
		{
			// Render the custom error page.
			JError::customErrorPage($error);
		}
	}
}
system/logout/logout.xml000064400000001403147357022250011441
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_logout</name>
	<author>Joomla! Project</author>
	<creationDate>April 2009</creationDate>
	<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_LOGOUT_XML_DESCRIPTION</description>
	<files>
		<filename plugin="logout">logout.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_logout.ini</language>
		<language
tag="en-GB">en-GB.plg_system_logout.sys.ini</language>
	</languages>
</extension>
system/logrotation/logrotation.php000064400000014202147357022250013511
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.logrotation
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;

/**
 * Joomla! Log Rotation plugin
 *
 * Rotate the log files created by Joomla core
 *
 * @since  3.9.0
 */
class PlgSystemLogrotation extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.9.0
	 */
	protected $db;

	/**
	 * The log check and rotation code is triggered after the page has fully
rendered.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onAfterRender()
	{
		// Get the timeout as configured in plugin parameters

		/** @var \Joomla\Registry\Registry $params */
		$cache_timeout = (int) $this->params->get('cachetimeout',
30);
		$cache_timeout = 24 * 3600 * $cache_timeout;
		$logsToKeep    = (int) $this->params->get('logstokeep',
1);

		// Do we need to run? Compare the last run timestamp stored in the
plugin's options with the current
		// timestamp. If the difference is greater than the cache timeout we
shall not execute again.
		$now  = time();
		$last = (int) $this->params->get('lastrun', 0);

		if ((abs($now - $last) < $cache_timeout))
		{
			return;
		}

		// Update last run status
		$this->params->set('lastrun', $now);

		$db    = $this->db;
		$query = $db->getQuery(true)
			->update($db->qn('#__extensions'))
			->set($db->qn('params') . ' = ' .
$db->q($this->params->toString('JSON')))
			->where($db->qn('type') . ' = ' .
$db->q('plugin'))
			->where($db->qn('folder') . ' = ' .
$db->q('system'))
			->where($db->qn('element') . ' = ' .
$db->q('logrotation'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race
condition
			$db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue
execution
			return;
		}

		try
		{
			// Update the plugin parameters
			$result = $db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		// Abort on failure
		if (!$result)
		{
			return;
		}

		// Get the log path
		$logPath = Path::clean($this->app->get('log_path'));

		// Invalid path, stop processing further
		if (!is_dir($logPath))
		{
			return;
		}

		$logFiles = $this->getLogFiles($logPath);

		// Sort log files by version number in reserve order
		krsort($logFiles, SORT_NUMERIC);

		foreach ($logFiles as $version => $files)
		{
			if ($version >= $logsToKeep)
			{
				// Delete files which has version greater than or equals $logsToKeep
				foreach ($files as $file)
				{
					File::delete($logPath . '/' . $file);
				}
			}
			else
			{
				// For files which has version smaller than $logsToKeep, rotate
(increase version number)
				foreach ($files as $file)
				{
					$this->rotate($logPath, $file, $version);
				}
			}
		}
	}

	/**
	 * Get log files from log folder
	 *
	 * @param   string  $path  The folder to get log files
	 *
	 * @return  array   The log files in the given path grouped by version
number (not rotated files has number 0)
	 *
	 * @since   3.9.0
	 */
	private function getLogFiles($path)
	{
		$logFiles = array();
		$files    = Folder::files($path, '\.php$');

		foreach ($files as $file)
		{
			$parts    = explode('.', $file);

			/*
			 * Rotated log file has this filename format [VERSION].[FILENAME].php.
So if $parts has at least 3 elements
			 * and the first element is a number, we know that it's a rotated
file and can get it's current version
			 */
			if (count($parts) >= 3 && is_numeric($parts[0]))
			{
				$version = (int) $parts[0];
			}
			else
			{
				$version = 0;
			}

			if (!isset($logFiles[$version]))
			{
				$logFiles[$version] = array();
			}

			$logFiles[$version][] = $file;
		}

		return $logFiles;
	}

	/**
	 * Method to rotate (increase version) of a log file
	 *
	 * @param   string  $path            Path to file to rotate
	 * @param   string  $filename        Name of file to rotate
	 * @param   int     $currentVersion  The current version number
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	private function rotate($path, $filename, $currentVersion)
	{
		if ($currentVersion === 0)
		{
			$rotatedFile = $path . '/1.' . $filename;
		}
		else
		{
			/*
			 * Rotated log file has this filename format [VERSION].[FILENAME].php.
To rotate it, we just need to explode
			 * the filename into an array, increase value of first element (keep
version) and implode it back to get the
			 * rotated file name
			 */
			$parts    = explode('.', $filename);
			$parts[0] = $currentVersion + 1;

			$rotatedFile = $path . '/' . implode('.', $parts);
		}

		File::move($path . '/' . $filename, $rotatedFile);
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
	{
		$conf = JFactory::getConfig();

		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $client_id ? JPATH_ADMINISTRATOR .
'/cache' :
							$conf->get('cache_path', JPATH_SITE .
'/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
system/logrotation/logrotation.xml000064400000003043147357022250013523
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="system" method="upgrade">
	<name>plg_system_logrotation</name>
	<author>Joomla! Project</author>
	<creationDate>May 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_SYSTEM_LOGROTATION_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="logrotation">logrotation.php</filename>
	</files>
	<languages folder="language">
		<language
tag="en-GB">en-GB.plg_system_logrotation.ini</language>
		<language
tag="en-GB">en-GB.plg_system_logrotation.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="cachetimeout"
					type="integer"
					label="PLG_SYSTEM_LOGROTATION_CACHETIMEOUT_LABEL"
					description="PLG_SYSTEM_LOGROTATION_CACHETIMEOUT_DESC"
					first="0"
					last="120"
					step="1"
					default="30"
					filter="int"
					validate="number"
				/>

				<field
					name="logstokeep"
					type="integer"
					label="PLG_SYSTEM_LOGROTATION_LOGSTOKEEP_LABEL"
					description="PLG_SYSTEM_LOGROTATION_LOGSTOKEEP_DESC"
					first="1"
					last="10"
					step="1"
					default="1"
					filter="int"
					validate="number"
				/>

				<field
					name="lastrun"
					type="hidden"
					default="0"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
system/p3p/p3p.php000064400000001610147357022250010012 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.p3p
 *
 * @copyright   (C) 2010 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! P3P Header Plugin.
 *
 * @since  1.6
 * @deprecate  4.0  Obsolete
 */
class PlgSystemP3p extends JPlugin
{
	/**
	 * After initialise.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 * @deprecate  4.0  Obsolete
	 */
	public function onAfterInitialise()
	{
		// Get the header.
		$header = $this->params->get('header', 'NOI ADM DEV
PSAi COM NAV OUR OTRo STP IND DEM');
		$header = trim($header);

		// Bail out on empty header (why would anyone do that?!).
		if (empty($header))
		{
			return;
		}

		// Replace any existing P3P headers in the response.
		JFactory::getApplication()->setHeader('P3P',
'CP="' . $header . '"', true);
	}
}
system/p3p/p3p.xml000064400000002044147357022250010025 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_p3p</name>
	<author>Joomla! Project</author>
	<creationDate>September 2010</creationDate>
	<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_P3P_XML_DESCRIPTION</description>
	<files>
		<filename plugin="p3p">p3p.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_p3p.ini</language>
		<language
tag="en-GB">en-GB.plg_system_p3p.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="header"
					type="text"
					label="PLG_P3P_HEADER_LABEL"
					description="PLG_P3P_HEADER_DESCRIPTION"
					default="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
					size="37"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
system/privacyconsent/field/privacy.php000064400000005223147357022250014421
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.privacyconsent
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;

JFormHelper::loadFieldClass('radio');

/**
 * Provides input for privacy
 *
 * @since  3.9.0
 */
class JFormFieldprivacy extends JFormFieldRadio
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $type = 'privacy';

	/**
	 * Method to get the field input markup.
	 *
	 * @return  string   The field input markup.
	 *
	 * @since   3.9.0
	 */
	protected function getInput()
	{
		// Display the message before the field
		echo
$this->getRenderer('plugins.system.privacyconsent.message')->render($this->getLayoutData());

		return parent::getInput();
	}

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   3.9.0
	 */
	protected function getLabel()
	{
		if ($this->hidden)
		{
			return '';
		}

		return
$this->getRenderer('plugins.system.privacyconsent.label')->render($this->getLayoutData());

	}

	/**
	 * Method to get the data to be passed to the layout for rendering.
	 *
	 * @return  array
	 *
	 * @since   3.9.4
	 */
	protected function getLayoutData()
	{
		$data = parent::getLayoutData();

		$article = false;
		$privacyArticle = $this->element['article'] > 0 ? (int)
$this->element['article'] : 0;

		if ($privacyArticle &&
Factory::getApplication()->isClient('site'))
		{
			$db    = Factory::getDbo();
			$query = $db->getQuery(true)
				->select($db->quoteName(array('id', 'alias',
'catid', 'language')))
				->from($db->quoteName('#__content'))
				->where($db->quoteName('id') . ' = ' . (int)
$privacyArticle);
			$db->setQuery($query);
			$article = $db->loadObject();

			JLoader::register('ContentHelperRoute', JPATH_BASE .
'/components/com_content/helpers/route.php');

			$slug = $article->alias ? ($article->id . ':' .
$article->alias) : $article->id;
			$article->link  = ContentHelperRoute::getArticleRoute($slug,
$article->catid, $article->language);
		}

		$extraData = array(
			'privacynote' =>
!empty($this->element['note']) ?
$this->element['note'] :
Text::_('PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_DEFAULT'),
			'options' => $this->getOptions(),
			'value'   => (string) $this->value,
			'translateLabel' => $this->translateLabel,
			'translateDescription' => $this->translateDescription,
			'translateHint' => $this->translateHint,
			'privacyArticle' => $privacyArticle,
			'article' => $article,
		);

		return array_merge($data, $extraData);
	}
}
system/privacyconsent/privacyconsent/privacyconsent.xml000064400000001072147357022250020006
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="privacyconsent">
		<fieldset
			name="privacyconsent"
			label="PLG_SYSTEM_PRIVACYCONSENT_LABEL"
		>
			<field
				name="privacy"
				type="privacy"
				label="PLG_SYSTEM_PRIVACYCONSENT_FIELD_LABEL"
				description="PLG_SYSTEM_PRIVACYCONSENT_FIELD_DESC"
				default="0"
				filter="integer"
				required="true"
				>
				<option
value="1">PLG_SYSTEM_PRIVACYCONSENT_OPTION_AGREE</option>
				<option
value="0">PLG_SYSTEM_PRIVACYCONSENT_OPTION_DO_NOT_AGREE</option>
			</field>
		</fieldset>
	</fields>
</form>
system/privacyconsent/privacyconsent.php000064400000046406147357022250014740
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.privacyconsent
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\Utilities\ArrayHelper;

/**
 * An example custom privacyconsent plugin.
 *
 * @since  3.9.0
 */
class PlgSystemPrivacyconsent extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.9.0
	 */
	protected $db;

	/**
	 * Constructor
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An array that holds the plugin
configuration
	 *
	 * @since   3.9.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		JFormHelper::addFieldPath(__DIR__ . '/field');
	}

	/**
	 * Adds additional fields to the user editing form
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareForm($form, $data)
	{
		if (!($form instanceof JForm))
		{
			$this->_subject->setError('JERROR_NOT_A_FORM');

			return false;
		}

		// Check we are manipulating a valid form - we only display this on user
registration form and user profile form.
		$name = $form->getName();

		if (!in_array($name, array('com_users.profile',
'com_users.registration')))
		{
			return true;
		}

		// We only display this if user has not consented before
		if (is_object($data))
		{
			$userId = isset($data->id) ? $data->id : 0;

			if ($userId > 0 && $this->isUserConsented($userId))
			{
				return true;
			}
		}

		// Add the privacy policy fields to the form.
		JForm::addFormPath(__DIR__ . '/privacyconsent');
		$form->loadFile('privacyconsent');

		$privacyArticleId = $this->getPrivacyArticleId();
		$privacynote      = $this->params->get('privacy_note');

		// Push the privacy article ID into the privacy field.
		$form->setFieldAttribute('privacy', 'article',
$privacyArticleId, 'privacyconsent');
		$form->setFieldAttribute('privacy', 'note',
$privacynote, 'privacyconsent');
	}

	/**
	 * Method is called before user data is stored in the database
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isNew  True if a new user is stored.
	 * @param   array    $data   Holds the new user data.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 * @throws  InvalidArgumentException on missing required data.
	 */
	public function onUserBeforeSave($user, $isNew, $data)
	{
		// // Only check for front-end user creation/update profile
		if ($this->app->isClient('administrator'))
		{
			return true;
		}

		$userId = ArrayHelper::getValue($user, 'id', 0,
'int');

		// User already consented before, no need to check it further
		if ($userId > 0 && $this->isUserConsented($userId))
		{
			return true;
		}

		// Check that the privacy is checked if required ie only in registration
from frontend.
		$option = $this->app->input->getCmd('option');
		$task   = $this->app->input->get->getCmd('task');
		$form   = $this->app->input->post->get('jform',
array(), 'array');

		if ($option == 'com_users' && in_array($task,
array('registration.register', 'profile.save'))
			&&
empty($form['privacyconsent']['privacy']))
		{
			throw new
InvalidArgumentException(Text::_('PLG_SYSTEM_PRIVACYCONSENT_FIELD_ERROR'));
		}

		return true;
	}

	/**
	 * Saves user privacy confirmation
	 *
	 * @param   array    $data    entered user data
	 * @param   boolean  $isNew   true if this is a new user
	 * @param   boolean  $result  true if saving the user worked
	 * @param   string   $error   error message
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSave($data, $isNew, $result, $error)
	{
		// Only create an entry on front-end user creation/update profile
		if ($this->app->isClient('administrator'))
		{
			return true;
		}

		// Get the user's ID
		$userId = ArrayHelper::getValue($data, 'id', 0,
'int');

		// If user already consented before, no need to check it further
		if ($userId > 0 && $this->isUserConsented($userId))
		{
			return true;
		}

		$option = $this->app->input->getCmd('option');
		$task   = $this->app->input->get->getCmd('task');
		$form   = $this->app->input->post->get('jform',
array(), 'array');

		if ($option == 'com_users'
			&&in_array($task, array('registration.register',
'profile.save'))
			&&
!empty($form['privacyconsent']['privacy']))
		{
			$userId = ArrayHelper::getValue($data, 'id', 0,
'int');

			// Get the user's IP address
			$ip =
$this->app->input->server->get('REMOTE_ADDR',
'', 'string');

			// Get the user agent string
			$userAgent =
$this->app->input->server->get('HTTP_USER_AGENT',
'', 'string');

			// Create the user note
			$userNote = (object) array(
				'user_id' => $userId,
				'subject' =>
'PLG_SYSTEM_PRIVACYCONSENT_SUBJECT',
				'body'    =>
Text::sprintf('PLG_SYSTEM_PRIVACYCONSENT_BODY', $ip, $userAgent),
				'created' => Factory::getDate()->toSql(),
			);

			try
			{
				$this->db->insertObject('#__privacy_consents',
$userNote);
			}
			catch (Exception $e)
			{
				// Do nothing if the save fails
			}

			$userId = ArrayHelper::getValue($data, 'id', 0,
'int');

			$message = array(
				'action'      => 'consent',
				'id'          => $userId,
				'title'       => $data['name'],
				'itemlink'    =>
'index.php?option=com_users&task=user.edit&id=' .
$userId,
				'userid'      => $userId,
				'username'    => $data['username'],
				'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$userId,
			);

			JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_actionlogs/models',
'ActionlogsModel');

			/* @var ActionlogsModelActionlog $model */
			$model = JModelLegacy::getInstance('Actionlog',
'ActionlogsModel');
			$model->addLog(array($message),
'PLG_SYSTEM_PRIVACYCONSENT_CONSENT',
'plg_system_privacyconsent', $userId);
		}

		return true;
	}

	/**
	 * Remove all user privacy consent information for the given user ID
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the
database
	 * @param   string   $msg      Message
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		$userId = ArrayHelper::getValue($user, 'id', 0,
'int');

		if ($userId)
		{
			// Remove user's consent
			try
			{
				$query = $this->db->getQuery(true)
					->delete($this->db->quoteName('#__privacy_consents'))
					->where($this->db->quoteName('user_id') . ' =
' . (int) $userId);
				$this->db->setQuery($query);
				$this->db->execute();
			}
			catch (Exception $e)
			{
				$this->_subject->setError($e->getMessage());

				return false;
			}
		}

		return true;
	}

	/**
	 * If logged in users haven't agreed to privacy consent, redirect
them to profile edit page, ask them to agree to
	 * privacy consent before allowing access to any other pages
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onAfterRoute()
	{
		// Run this in frontend only
		if ($this->app->isClient('administrator'))
		{
			return;
		}

		$userId = Factory::getUser()->id;

		// Check to see whether user already consented, if not, redirect to user
profile page
		if ($userId > 0)
		{
			// If user consented before, no need to check it further
			if ($this->isUserConsented($userId))
			{
				return;
			}

			$option = $this->app->input->getCmd('option');
			$task   = $this->app->input->get('task');
			$view   = $this->app->input->getString('view',
'');
			$layout = $this->app->input->getString('layout',
'');
			$id     = $this->app->input->getInt('id');

			$privacyArticleId = $this->getPrivacyArticleId();

			/*
			 * If user is already on edit profile screen or view privacy article
			 * or press update/apply button, or logout, do nothing to avoid infinite
redirect
			 */
			if ($option == 'com_users' && in_array($task,
array('profile.save', 'profile.apply',
'user.logout', 'user.menulogout'))
				|| ($option == 'com_content' && $view ==
'article' && $id == $privacyArticleId)
				|| ($option == 'com_users' && $view ==
'profile' && $layout == 'edit'))
			{
				return;
			}

			// Redirect to com_users profile edit
			$this->app->enqueueMessage($this->getRedirectMessage(),
'notice');
			$link =
'index.php?option=com_users&view=profile&layout=edit';
			$this->app->redirect(\JRoute::_($link, false));
		}
	}

	/**
	 * Event to specify whether a privacy policy has been published.
	 *
	 * @param   array  &$policy  The privacy policy status data, passed by
reference, with keys "published", "editLink" and
"articlePublished".
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onPrivacyCheckPrivacyPolicyPublished(&$policy)
	{
		// If another plugin has already indicated a policy is published, we
won't change anything here
		if ($policy['published'])
		{
			return;
		}

		$articleId = $this->params->get('privacy_article');

		if (!$articleId)
		{
			return;
		}

		// Check if the article exists in database and is published
		$query = $this->db->getQuery(true)
			->select($this->db->quoteName(array('id',
'state')))
			->from($this->db->quoteName('#__content'))
			->where($this->db->quoteName('id') . ' = '
. (int) $articleId);
		$this->db->setQuery($query);

		$article = $this->db->loadObject();

		// Check if the article exists
		if (!$article)
		{
			return;
		}

		// Check if the article is published
		if ($article->state == 1)
		{
			$policy['articlePublished'] = true;
		}

		$policy['published'] = true;
		$policy['editLink']  =
JRoute::_('index.php?option=com_content&task=article.edit&id='
. $articleId);
	}

	/**
	 * Returns the configured redirect message and falls back to the default
version.
	 *
	 * @return  string  redirect message
	 *
	 * @since   3.9.0
	 */
	private function getRedirectMessage()
	{
		$messageOnRedirect =
trim($this->params->get('messageOnRedirect',
''));

		if (empty($messageOnRedirect))
		{
			return
Text::_('PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_DEFAULT');
		}

		return $messageOnRedirect;
	}

	/**
	 * Method to check if the given user has consented yet
	 *
	 * @param   integer  $userId  ID of uer to check
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	private function isUserConsented($userId)
	{
		$query = $this->db->getQuery(true);
		$query->select('COUNT(*)')
			->from('#__privacy_consents')
			->where('user_id = ' . (int) $userId)
			->where('subject = ' .
$this->db->quote('PLG_SYSTEM_PRIVACYCONSENT_SUBJECT'))
			->where('state = 1');
		$this->db->setQuery($query);

		return (int) $this->db->loadResult() > 0;
	}

	/**
	 * Get privacy article ID. If the site is a multilingual website and there
is associated article for the
	 * current language, ID of the associated article will be returned
	 *
	 * @return  integer
	 *
	 * @since   3.9.0
	 */
	private function getPrivacyArticleId()
	{
		$privacyArticleId =
$this->params->get('privacy_article');

		if ($privacyArticleId > 0 &&
JLanguageAssociations::isEnabled())
		{
			$privacyAssociated =
JLanguageAssociations::getAssociations('com_content',
'#__content', 'com_content.item', $privacyArticleId);
			$currentLang = JFactory::getLanguage()->getTag();

			if (isset($privacyAssociated[$currentLang]))
			{
				$privacyArticleId = $privacyAssociated[$currentLang]->id;
			}
		}

		return $privacyArticleId;
	}

	/**
	 * The privacy consent expiration check code is triggered after the page
has fully rendered.
	 *
	 * @return  void
	 *
	 * @since   3.9.0
	 */
	public function onAfterRender()
	{
		if (!$this->params->get('enabled', 0))
		{
			return;
		}

		$cacheTimeout = (int) $this->params->get('cachetimeout',
30);
		$cacheTimeout = 24 * 3600 * $cacheTimeout;

		// Do we need to run? Compare the last run timestamp stored in the
plugin's options with the current
		// timestamp. If the difference is greater than the cache timeout we
shall not execute again.
		$now  = time();
		$last = (int) $this->params->get('lastrun', 0);

		if ((abs($now - $last) < $cacheTimeout))
		{
			return;
		}

		// Update last run status
		$this->params->set('lastrun', $now);
		$db    = $this->db;
		$query = $db->getQuery(true)
			->update($db->quoteName('#__extensions'))
			->set($db->quoteName('params') . ' = ' .
$db->quote($this->params->toString('JSON')))
			->where($db->quoteName('type') . ' = ' .
$db->quote('plugin'))
			->where($db->quoteName('folder') . ' = ' .
$db->quote('system'))
			->where($db->quoteName('element') . ' = ' .
$db->quote('privacyconsent'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race
condition
			$db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue
execution
			return;
		}

		try
		{
			// Update the plugin parameters
			$result = $db->setQuery($query)->execute();
			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		// Abort on failure
		if (!$result)
		{
			return;
		}

		// Delete the expired privacy consents
		$this->invalidateExpiredConsents();

		// Remind for privacy consents near to expire
		$this->remindExpiringConsents();

	}

	/**
	 * Method to send the remind for privacy consents renew
	 *
	 * @return  integer
	 *
	 * @since   3.9.0
	 */
	private function remindExpiringConsents()
	{
		// Load the parameters.
		$expire = (int) $this->params->get('consentexpiration',
365);
		$remind = (int) $this->params->get('remind', 30);
		$now    = JFactory::getDate()->toSql();
		$period = '-' . ($expire - $remind);

		$db    = $this->db;
		$query = $db->getQuery(true)
			->select($db->quoteName(array('r.id',
'r.user_id', 'u.email')))
			->from($db->quoteName('#__privacy_consents',
'r'))
			->leftJoin($db->quoteName('#__users', 'u') .
' ON u.id = r.user_id')
			->where($db->quoteName('subject') . ' = ' .
$db->quote('PLG_SYSTEM_PRIVACYCONSENT_SUBJECT'))
			->where($db->quoteName('remind') . ' = 0');
		$query->where($query->dateAdd($db->quote($now), $period,
'DAY') . ' > ' .
$db->quoteName('created'));

		try
		{
			$users = $db->setQuery($query)->loadObjectList();
		}
		catch (JDatabaseException $exception)
		{
			return false;
		}

		$app      = JFactory::getApplication();
		$linkMode = $app->get('force_ssl', 0) == 2 ?
Route::TLS_FORCE : Route::TLS_IGNORE;

		foreach ($users as $user)
		{
			$token       =
JApplicationHelper::getHash(JUserHelper::genRandomPassword());
			$hashedToken = JUserHelper::hashPassword($token);

			// The mail
			try
			{
				$substitutions = array(
					'[SITENAME]' => $app->get('sitename'),
					'[URL]'      => JUri::root(),
					'[TOKENURL]' => JRoute::link('site',
'index.php?option=com_privacy&view=remind&remind_token='
. $token, false, $linkMode, true),
					'[FORMURL]'  => JRoute::link('site',
'index.php?option=com_privacy&view=remind', false, $linkMode,
true),
					'[TOKEN]'    => $token,
					'\\n'        => "\n",
				);

				$emailSubject =
JText::_('PLG_SYSTEM_PRIVACYCONSENT_EMAIL_REMIND_SUBJECT');
				$emailBody =
JText::_('PLG_SYSTEM_PRIVACYCONSENT_EMAIL_REMIND_BODY');

				foreach ($substitutions as $k => $v)
				{
					$emailSubject = str_replace($k, $v, $emailSubject);
					$emailBody    = str_replace($k, $v, $emailBody);
				}

				$mailer = JFactory::getMailer();
				$mailer->setSubject($emailSubject);
				$mailer->setBody($emailBody);
				$mailer->addRecipient($user->email);

				$mailResult = $mailer->Send();

				if ($mailResult instanceof JException)
				{
					return false;
				}
				elseif ($mailResult === false)
				{
					return false;
				}

				// Update the privacy_consents item to not send the reminder again
				$query->clear()
					->update($db->quoteName('#__privacy_consents'))
					->set($db->quoteName('remind') . ' = 1 ')
					->set($db->quoteName('token') . ' = ' .
$db->quote($hashedToken))
					->where($db->quoteName('id') . ' = ' . (int)
$user->id);
				$db->setQuery($query);

				try
				{
					$db->execute();
				}
				catch (RuntimeException $e)
				{
					return false;
				}
			}
			catch (phpmailerException $exception)
			{
				return false;
			}
		}
	}

	/**
	 * Method to delete the expired privacy consents
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	private function invalidateExpiredConsents()
	{
		// Load the parameters.
		$expire = (int) $this->params->get('consentexpiration',
365);
		$now    = JFactory::getDate()->toSql();
		$period = '-' . $expire;

		$db    = $this->db;
		$query = $db->getQuery(true);
		$query->select($db->quoteName(array('id',
'user_id')))
			->from($db->quoteName('#__privacy_consents'))
			->where($query->dateAdd($db->quote($now), $period,
'DAY') . ' > ' .
$db->quoteName('created'))
			->where($db->quoteName('subject') . ' = ' .
$db->quote('PLG_SYSTEM_PRIVACYCONSENT_SUBJECT'))
			->where($db->quoteName('state') . ' = 1');
		$db->setQuery($query);

		try
		{
			$users = $db->loadObjectList();
		}
		catch (RuntimeException $e)
		{
			return false;
		}

		// Do not process further if no expired consents found
		if (empty($users))
		{
			return true;
		}

		// Push a notification to the site's super users
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_messages/models', 'MessagesModel');
		JTable::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_messages/tables');
		/** @var MessagesModelMessage $messageModel */
		$messageModel = JModelLegacy::getInstance('Message',
'MessagesModel');

		foreach ($users as $user)
		{
			$query = $db->getQuery(true)
				->update($db->quoteName('#__privacy_consents'))
				->set('state = 0')
				->where($db->quoteName('id') . ' = ' . (int)
$user->id);
			$db->setQuery($query);

			try
			{
				$db->execute();
			}
			catch (RuntimeException $e)
			{
				return false;
			}

			$messageModel->notifySuperUsers(
				JText::_('PLG_SYSTEM_PRIVACYCONSENT_NOTIFICATION_USER_PRIVACY_EXPIRED_SUBJECT'),
				JText::sprintf('PLG_SYSTEM_PRIVACYCONSENT_NOTIFICATION_USER_PRIVACY_EXPIRED_MESSAGE',
JFactory::getUser($user->user_id)->username)
			);
		}

		return true;
	}
	/**
	 * Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since    3.9.0
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
	{
		$conf = JFactory::getConfig();

		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $client_id ? JPATH_ADMINISTRATOR .
'/cache' :
							$conf->get('cache_path', JPATH_SITE .
'/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
system/privacyconsent/privacyconsent.xml000064400000006512147357022250014743
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="plugin"
group="system" method="upgrade">
	<name>plg_system_privacyconsent</name>
	<author>Joomla! Project</author>
	<creationDate>April 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_SYSTEM_PRIVACYCONSENT_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="privacyconsent">privacyconsent.php</filename>
		<folder>privacyconsent</folder>
		<folder>field</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_privacyconsent.ini</language>
		<language
tag="en-GB">en-GB.plg_system_privacyconsent.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic"
addfieldpath="/administrator/components/com_content/models/fields">
				<field
					name="privacy_note"
					type="textarea"
					label="PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_DESC"
					hint="PLG_SYSTEM_PRIVACYCONSENT_NOTE_FIELD_DEFAULT"
					class="span12"
					rows="7"
					cols="20"
					filter="html"
				/>
				<field
					name="privacy_article"
					type="modal_article"
					label="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ARTICLE_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ARTICLE_DESC"
					select="true"
					new="true"
					edit="true"
					clear="true"
					filter="integer"
				/>
				<field
					name="messageOnRedirect"
					type="textarea"
					label="PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_DESC"
					hint="PLG_SYSTEM_PRIVACYCONSENT_REDIRECT_MESSAGE_DEFAULT"
					class="span12"
					rows="7"
					cols="20"
					filter="html"
				/>
			</fieldset>
			<fieldset
				name="expiration"
				label="PLG_SYSTEM_PRIVACYCONSENT_EXPIRATION_FIELDSET_LABEL"
			>
				<field
					name="enabled"
					type="radio"
					label="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ENABLED_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_FIELD_ENABLED_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
				<field
					name="cachetimeout"
					type="integer"
					label="PLG_SYSTEM_PRIVACYCONSENT_CACHETIMEOUT_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_CACHETIMEOUT_DESC"
					first="0"
					last="120"
					step="1"
					default="30"
					filter="int"
					validate="number"
				/>
				<field
					name="consentexpiration"
					type="integer"
					label="PLG_SYSTEM_PRIVACYCONSENT_CONSENTEXPIRATION_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_CONSENTEXPIRATION_DESC"
					first="180"
					last="720"
					step="30"
					default="360"
					filter="int"
					validate="number"
				/>
				<field
					name="remind"
					type="integer"
					label="PLG_SYSTEM_PRIVACYCONSENT_REMINDBEFORE_LABEL"
					description="PLG_SYSTEM_PRIVACYCONSENT_REMINDBEFORE_DESC"
					first="0"
					last="120"
					step="1"
					default="30"
					filter="int"
					validate="number"
				/>
				<field
					name="lastrun"
					type="hidden"
					default="0"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
system/redirect/form/excludes.xml000064400000000726147357022250013206
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fieldset>
		<field
			name="term"
			type="text"
			label="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_TERM_LABEL"
			description="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_TERM_DESC"
			required="true"
		/>
		<field
			name="regexp"
			type="checkbox"
			label="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_REGEXP_LABEL"
			description="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_REGEXP_DESC"
			filter="integer"
		/>
	</fieldset>
</form>
system/redirect/redirect.php000064400000023045147357022250012216
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.redirect
 *
 * @copyright   (C) 2009 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\Registry\Registry;
use Joomla\String\StringHelper;

/**
 * Plugin class for redirect handling.
 *
 * @since  1.6
 */
class PlgSystemRedirect extends JPlugin
{
	/**
	 * Affects constructor behavior. If true, language files will be loaded
automatically.
	 *
	 * @var    boolean
	 * @since  3.4
	 */
	protected $autoloadLanguage = false;

	/**
	 * The global exception handler registered before the plugin was
instantiated
	 *
	 * @var    callable
	 * @since  3.6
	 */
	private static $previousExceptionHandler;

	/**
	 * Constructor.
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An optional associative array of
configuration settings.
	 *
	 * @since   1.6
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		// Set the JError handler for E_ERROR to be the class' handleError
method.
		JError::setErrorHandling(E_ERROR, 'callback',
array('PlgSystemRedirect', 'handleError'));

		// Register the previously defined exception handler so we can forward
errors to it
		self::$previousExceptionHandler =
set_exception_handler(array('PlgSystemRedirect',
'handleException'));
	}

	/**
	 * Method to handle an error condition from JError.
	 *
	 * @param   JException  $error  The JException object to be handled.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public static function handleError(JException $error)
	{
		self::doErrorHandling($error);
	}

	/**
	 * Method to handle an uncaught exception.
	 *
	 * @param   Exception|Throwable  $exception  The Exception or Throwable
object to be handled.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 * @throws  InvalidArgumentException
	 */
	public static function handleException($exception)
	{
		// If this isn't a Throwable then bail out
		if (!($exception instanceof Throwable) && !($exception instanceof
Exception))
		{
			throw new InvalidArgumentException(
				sprintf('The error handler requires an Exception or Throwable
object, a "%s" object was given instead.',
get_class($exception))
			);
		}

		self::doErrorHandling($exception);
	}

	/**
	 * Internal processor for all error handlers
	 *
	 * @param   Exception|Throwable  $error  The Exception or Throwable object
to be handled.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	private static function doErrorHandling($error)
	{
		$app = JFactory::getApplication();

		if ($app->isClient('administrator') || ((int)
$error->getCode() !== 404))
		{
			// Proxy to the previous exception handler if available, otherwise just
render the error page
			if (self::$previousExceptionHandler)
			{
				call_user_func_array(self::$previousExceptionHandler, array($error));
			}
			else
			{
				JErrorPage::render($error);
			}
		}

		$uri = JUri::getInstance();

		// These are the original URLs
		$orgurl                =
rawurldecode($uri->toString(array('scheme', 'host',
'port', 'path', 'query',
'fragment')));
		$orgurlRel             =
rawurldecode($uri->toString(array('path', 'query',
'fragment')));

		// The above doesn't work for sub directories, so do this
		$orgurlRootRel         = str_replace(JUri::root(), '',
$orgurl);

		// For when users have added / to the url
		$orgurlRootRelSlash    = str_replace(JUri::root(), '/',
$orgurl);
		$orgurlWithoutQuery    =
rawurldecode($uri->toString(array('scheme', 'host',
'port', 'path', 'fragment')));
		$orgurlRelWithoutQuery =
rawurldecode($uri->toString(array('path',
'fragment')));

		// These are the URLs we save and use
		$url                =
StringHelper::strtolower(rawurldecode($uri->toString(array('scheme',
'host', 'port', 'path', 'query',
'fragment'))));
		$urlRel             =
StringHelper::strtolower(rawurldecode($uri->toString(array('path',
'query', 'fragment'))));

		// The above doesn't work for sub directories, so do this
		$urlRootRel         = str_replace(JUri::root(), '', $url);

		// For when users have added / to the url
		$urlRootRelSlash    = str_replace(JUri::root(), '/', $url);
		$urlWithoutQuery    =
StringHelper::strtolower(rawurldecode($uri->toString(array('scheme',
'host', 'port', 'path',
'fragment'))));
		$urlRelWithoutQuery =
StringHelper::strtolower(rawurldecode($uri->toString(array('path',
'fragment'))));

		$plugin = JPluginHelper::getPlugin('system',
'redirect');

		$params = new Registry($plugin->params);

		$excludes = (array) $params->get('exclude_urls');

		$skipUrl = false;

		foreach ($excludes as $exclude)
		{
			if (empty($exclude->term))
			{
				continue;
			}

			if (!empty($exclude->regexp))
			{
				// Only check $url, because it includes all other sub urls
				if (preg_match('/' . $exclude->term . '/i',
$orgurlRel))
				{
					$skipUrl = true;
					break;
				}
			}
			else
			{
				if (StringHelper::strpos($orgurlRel, $exclude->term) !== false)
				{
					$skipUrl = true;
					break;
				}
			}
		}

		// Why is this (still) here?
		if ($skipUrl || (strpos($url, 'mosConfig_') !== false) ||
(strpos($url, '=http://') !== false))
		{
			JErrorPage::render($error);
		}

		$db = JFactory::getDbo();

		$query = $db->getQuery(true);

		$query->select('*')
			->from($db->quoteName('#__redirect_links'))
			->where(
				'('
				. $db->quoteName('old_url') . ' = ' .
$db->quote($url)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($urlRel)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($urlRootRel)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($urlRootRelSlash)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($urlWithoutQuery)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($urlRelWithoutQuery)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurl)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlRel)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlRootRel)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlRootRelSlash)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlWithoutQuery)
				. ' OR '
				. $db->quoteName('old_url') . ' = ' .
$db->quote($orgurlRelWithoutQuery)
				. ')'
			);

		$db->setQuery($query);

		$redirect = null;

		try
		{
			$redirects = $db->loadAssocList();
		}
		catch (Exception $e)
		{
			JErrorPage::render(new
Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'),
500, $e));
		}

		$possibleMatches = array_unique(
			array(
				$url,
				$urlRel,
				$urlRootRel,
				$urlRootRelSlash,
				$urlWithoutQuery,
				$urlRelWithoutQuery,
				$orgurl,
				$orgurlRel,
				$orgurlRootRel,
				$orgurlRootRelSlash,
				$orgurlWithoutQuery,
				$orgurlRelWithoutQuery,
			)
		);

		foreach ($possibleMatches as $match)
		{
			if (($index = array_search($match, array_column($redirects,
'old_url'))) !== false)
			{
				$redirect = (object) $redirects[$index];

				if ((int) $redirect->published === 1)
				{
					break;
				}
			}
		}

		// A redirect object was found and, if published, will be used
		if ($redirect !== null && ((int) $redirect->published === 1))
		{
			if (!$redirect->header || (bool)
JComponentHelper::getParams('com_redirect')->get('mode',
false) === false)
			{
				$redirect->header = 301;
			}

			if ($redirect->header < 400 && $redirect->header >=
300)
			{
				$urlQuery = $uri->getQuery();

				$oldUrlParts = parse_url($redirect->old_url);

				$newUrl = $redirect->new_url;

				if ($urlQuery !== '' &&
empty($oldUrlParts['query']))
				{
					$newUrl .= '?' . $urlQuery;
				}

				$dest = JUri::isInternal($newUrl) || strpos($newUrl, 'http')
=== false ?
					JRoute::_($newUrl) : $newUrl;

				// In case the url contains double // lets remove it
				$destination = str_replace(JUri::root() . '/', JUri::root(),
$dest);

				// Always count redirect hits
				$redirect->hits++;

				try
				{
					$db->updateObject('#__redirect_links', $redirect,
'id');
				}
				catch (Exception $e)
				{
					// We don't log issues for now
				}

				$app->redirect($destination, (int) $redirect->header);
			}

			JErrorPage::render(new RuntimeException($error->getMessage(),
$redirect->header, $error));
		}
		// No redirect object was found so we create an entry in the redirect
table
		elseif ($redirect === null)
		{
			$params = new Registry(JPluginHelper::getPlugin('system',
'redirect')->params);

			if ((bool) $params->get('collect_urls', 1))
			{
				if (!$params->get('includeUrl', 1))
				{
					$url = $urlRel;
				}

				$data = (object) array(
					'id' => 0,
					'old_url' => $url,
					'referer' =>
$app->input->server->getString('HTTP_REFERER',
''),
					'hits' => 1,
					'published' => 0,
					'created_date' => JFactory::getDate()->toSql()
				);

				try
				{
					$db->insertObject('#__redirect_links', $data,
'id');
				}
				catch (Exception $e)
				{
					JErrorPage::render(new
Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'),
500, $e));
				}
			}
		}
		// We have an unpublished redirect object, increment the hit counter
		else
		{
			$redirect->hits++;

			try
			{
				$db->updateObject('#__redirect_links', $redirect,
'id');
			}
			catch (Exception $e)
			{
				JErrorPage::render(new
Exception(JText::_('PLG_SYSTEM_REDIRECT_ERROR_UPDATING_DATABASE'),
500, $e));
			}
		}

		// Proxy to the previous exception handler if available, otherwise just
render the error page
		if (self::$previousExceptionHandler)
		{
			call_user_func_array(self::$previousExceptionHandler, array($error));
		}
		else
		{
			JErrorPage::render($error);
		}
	}
}
system/redirect/redirect.xml000064400000003524147357022250012227
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_redirect</name>
	<author>Joomla! Project</author>
	<creationDate>April 2009</creationDate>
	<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SYSTEM_REDIRECT_XML_DESCRIPTION</description>
	<files>
		<folder>form</folder>
		<filename plugin="redirect">redirect.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_redirect.ini</language>
		<language
tag="en-GB">en-GB.plg_system_redirect.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="collect_urls"
					type="radio"
					label="PLG_SYSTEM_REDIRECT_FIELD_COLLECT_URLS_LABEL"
					description="PLG_SYSTEM_REDIRECT_FIELD_COLLECT_URLS_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JENABLED</option>
					<option value="0">JDISABLED</option>
				</field>
				<field
					name="includeUrl"
					type="radio"
					label="PLG_SYSTEM_REDIRECT_FIELD_STORE_FULL_URL_LABEL"
					description="PLG_SYSTEM_REDIRECT_FIELD_STORE_FULL_URL_DESC"
					default="1"
					filter="integer"
					class="btn-group btn-group-yesno"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
				<field
					name="exclude_urls"
					type="subform"
					label="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_LABEL"
					description="PLG_SYSTEM_REDIRECT_FIELD_EXCLUDE_URLS_DESC"
					multiple="true"
					formsource="plugins/system/redirect/form/excludes.xml"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
system/remember/remember.php000064400000006607147357022250012215
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.remember
 *
 * @copyright   (C) 2007 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! System Remember Me Plugin
 *
 * @since  1.5
 */

class PlgSystemRemember extends JPlugin
{
	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.2
	 */
	protected $app;

	/**
	 * Remember me method to run onAfterInitialise
	 * Only purpose is to initialise the login authentication process if a
cookie is present
	 *
	 * @return  void
	 *
	 * @since   1.5
	 * @throws  InvalidArgumentException
	 */
	public function onAfterInitialise()
	{
		// Get the application if not done by JPlugin. This may happen during
upgrades from Joomla 2.5.
		if (!$this->app)
		{
			$this->app = JFactory::getApplication();
		}

		// No remember me for admin.
		if ($this->app->isClient('administrator'))
		{
			return;
		}

		// Check for a cookie if user is not logged in
		if (JFactory::getUser()->get('guest'))
		{
			$cookieName = 'joomla_remember_me_' .
JUserHelper::getShortHashedUserAgent();

			// Try with old cookieName (pre 3.6.0) if not found
			if (!$this->app->input->cookie->get($cookieName))
			{
				$cookieName = JUserHelper::getShortHashedUserAgent();
			}

			// Check for the cookie
			if ($this->app->input->cookie->get($cookieName))
			{
				$this->app->login(array('username' => ''),
array('silent' => true));
			}
		}
	}

	/**
	 * Imports the authentication plugin on user logout to make sure that the
cookie is destroyed.
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (remember,
autoregister, group).
	 *
	 * @return  boolean
	 */
	public function onUserLogout($user, $options)
	{
		// No remember me for admin
		if ($this->app->isClient('administrator'))
		{
			return true;
		}

		$cookieName = 'joomla_remember_me_' .
JUserHelper::getShortHashedUserAgent();

		// Check for the cookie
		if ($this->app->input->cookie->get($cookieName))
		{
			// Make sure authentication group is loaded to process onUserAfterLogout
event
			JPluginHelper::importPlugin('authentication');
		}

		return true;
	}

	/**
	 * Method is called before user data is stored in the database
	 * Invalidate all existing remember-me cookies after a password change
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isnew  True if a new user is stored.
	 * @param   array    $data   Holds the new user data.
	 *
	 * @return    boolean
	 *
	 * @since   3.8.6
	 */
	public function onUserBeforeSave($user, $isnew, $data)
	{
		// Irrelevant on new users
		if ($isnew)
		{
			return true;
		}

		// Irrelevant, because password was not changed by user
		if (empty($data['password_clear']))
		{
			return true;
		}

		/*
		 * But now, we need to do something 
		 * Delete all tokens for this user!
		 */
		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
			->delete('#__user_keys')
			->where($db->quoteName('user_id') . ' = ' .
$db->quote($user['username']));
		try
		{
			$db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			// Log an alert for the site admin
			JLog::add(
				sprintf('Failed to delete cookie token for user %s with the
following error: %s', $user['username'],
$e->getMessage()),
				JLog::WARNING,
				'security'
			);
		}

		return true;
	}
}
system/remember/remember.xml000064400000001410147357022250012211
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_remember</name>
	<author>Joomla! Project</author>
	<creationDate>April 2007</creationDate>
	<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_REMEMBER_XML_DESCRIPTION</description>
	<files>
		<filename plugin="remember">remember.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_remember.ini</language>
		<language
tag="en-GB">en-GB.plg_system_remember.sys.ini</language>
	</languages>
</extension>
system/sef/sef.php000064400000016210147357022250010142 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.sef
 *
 * @copyright   (C) 2007 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! SEF Plugin.
 *
 * @since  1.5
 */
class PlgSystemSef extends JPlugin
{
	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.5
	 */
	protected $app;

	/**
	 * Add the canonical uri to the head.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	public function onAfterDispatch()
	{
		$doc = $this->app->getDocument();

		if (!$this->app->isClient('site') || $doc->getType()
!== 'html')
		{
			return;
		}

		$sefDomain = $this->params->get('domain', false);

		// Don't add a canonical html tag if no alternative domain has added
in SEF plugin domain field.
		if (empty($sefDomain))
		{
			return;
		}

		// Check if a canonical html tag already exists (for instance, added by a
component).
		$canonical = '';

		foreach ($doc->_links as $linkUrl => $link)
		{
			if (isset($link['relation']) &&
$link['relation'] === 'canonical')
			{
				$canonical = $linkUrl;
				break;
			}
		}

		// If a canonical html tag already exists get the canonical and change it
to use the SEF plugin domain field.
		if (!empty($canonical))
		{
			// Remove current canonical link.
			unset($doc->_links[$canonical]);

			// Set the current canonical link but use the SEF system plugin domain
field.
			$canonical = $sefDomain .
JUri::getInstance($canonical)->toString(array('path',
'query', 'fragment'));
		}
		// If a canonical html doesn't exists already add a canonical html
tag using the SEF plugin domain field.
		else
		{
			$canonical = $sefDomain .
JUri::getInstance()->toString(array('path', 'query',
'fragment'));
		}

		// Add the canonical link.
		$doc->addHeadLink(htmlspecialchars($canonical),
'canonical');
	}

	/**
	 * Convert the site URL to fit to the HTTP request.
	 *
	 * @return  void
	 */
	public function onAfterRender()
	{
		if (!$this->app->isClient('site'))
		{
			return;
		}

		// Replace src links.
		$base   = JUri::base(true) . '/';
		$buffer = $this->app->getBody();

		// For feeds we need to search for the URL with domain.
		$prefix = $this->app->getDocument()->getType() ===
'feed' ? JUri::root() : '';

		// Replace index.php URI by SEF URI.
		if (strpos($buffer, 'href="' . $prefix .
'index.php?') !== false)
		{
			preg_match_all('#href="' . $prefix .
'index.php\?([^"]+)"#m', $buffer, $matches);

			foreach ($matches[1] as $urlQueryString)
			{
				$buffer = str_replace(
					'href="' . $prefix . 'index.php?' .
$urlQueryString . '"',
					'href="' . trim($prefix, '/') .
JRoute::_('index.php?' . $urlQueryString) . '"',
					$buffer
				);
			}

			$this->checkBuffer($buffer);
		}

		// Check for all unknown protocols (a protocol must contain at least one
alphanumeric character followed by a ":").
		$protocols  = '[a-zA-Z0-9\-]+:';
		$attributes = array('href=', 'src=',
'poster=');

		foreach ($attributes as $attribute)
		{
			if (strpos($buffer, $attribute) !== false)
			{
				$regex  = '#\s' . $attribute . '"(?!/|' .
$protocols . '|\#|\')([^"]*)"#m';
				$buffer = preg_replace($regex, ' ' . $attribute .
'"' . $base . '$1"', $buffer);
				$this->checkBuffer($buffer);
			}
		}

		if (strpos($buffer, 'srcset=') !== false)
		{
			$regex = '#\s+srcset="([^"]+)"#m';

			$buffer = preg_replace_callback(
				$regex,
				function ($match) use ($base, $protocols)
				{
					preg_match_all('#(?:[^\s]+)\s*(?:[\d\.]+[wx])?(?:\,\s*)?#i',
$match[1], $matches);

					foreach ($matches[0] as &$src)
					{
						$src = preg_replace('#^(?!/|' . $protocols .
'|\#|\')(.+)#', $base . '$1', $src);
					}

					return ' srcset="' . implode($matches[0]) .
'"';
				},
				$buffer
			);

			$this->checkBuffer($buffer);
		}

		// Replace all unknown protocols in javascript window open events.
		if (strpos($buffer, 'window.open(') !== false)
		{
			$regex  = '#onclick="window.open\(\'(?!/|' .
$protocols . '|\#)([^/]+[^\']*?\')#m';
			$buffer = preg_replace($regex,
'onclick="window.open(\'' . $base . '$1',
$buffer);
			$this->checkBuffer($buffer);
		}

		// Replace all unknown protocols in onmouseover and onmouseout
attributes.
		$attributes = array('onmouseover=', 'onmouseout=');

		foreach ($attributes as $attribute)
		{
			if (strpos($buffer, $attribute) !== false)
			{
				$regex  = '#' . $attribute .
'"this.src=([\']+)(?!/|' . $protocols .
'|\#|\')([^"]+)"#m';
				$buffer = preg_replace($regex, $attribute .
'"this.src=$1' . $base . '$2"', $buffer);
				$this->checkBuffer($buffer);
			}
		}

		// Replace all unknown protocols in CSS background image.
		if (strpos($buffer, 'style=') !== false)
		{
			$regex_url  =
'\s*url\s*\(([\'\"]|\&\#0?3[49];)?(?!/|\&\#0?3[49];|'
. $protocols .
'|\#)([^\)\'\"]+)([\'\"]|\&\#0?3[49];)?\)';
			$regex  = '#style=\s*([\'\"])(.*):' . $regex_url .
'#m';
			$buffer = preg_replace($regex, 'style=$1$2: url($3' . $base .
'$4$5)', $buffer);
			$this->checkBuffer($buffer);
		}

		// Replace all unknown protocols in OBJECT param tag.
		if (strpos($buffer, '<param') !== false)
		{
			// OBJECT <param name="xx", value="yy"> -- fix
it only inside the <param> tag.
			$regex  =
'#(<param\s+)name\s*=\s*"(movie|src|url)"[^>]\s*value\s*=\s*"(?!/|'
. $protocols . '|\#|\')([^"]*)"#m';
			$buffer = preg_replace($regex, '$1name="$2"
value="' . $base . '$3"', $buffer);
			$this->checkBuffer($buffer);

			// OBJECT <param value="xx", name="yy"> -- fix
it only inside the <param> tag.
			$regex  = '#(<param\s+[^>]*)value\s*=\s*"(?!/|' .
$protocols .
'|\#|\')([^"]*)"\s*name\s*=\s*"(movie|src|url)"#m';
			$buffer = preg_replace($regex, '<param value="' .
$base . '$2" name="$3"', $buffer);
			$this->checkBuffer($buffer);
		}

		// Replace all unknown protocols in OBJECT tag.
		if (strpos($buffer, '<object') !== false)
		{
			$regex  = '#(<object\s+[^>]*)data\s*=\s*"(?!/|' .
$protocols . '|\#|\')([^"]*)"#m';
			$buffer = preg_replace($regex, '$1data="' . $base .
'$2"', $buffer);
			$this->checkBuffer($buffer);
		}

		// Use the replaced HTML body.
		$this->app->setBody($buffer);
	}

	/**
	 * Check the buffer.
	 *
	 * @param   string  $buffer  Buffer to be checked.
	 *
	 * @return  void
	 */
	private function checkBuffer($buffer)
	{
		if ($buffer === null)
		{
			switch (preg_last_error())
			{
				case PREG_BACKTRACK_LIMIT_ERROR:
					$message = 'PHP regular expression limit reached
(pcre.backtrack_limit)';
					break;
				case PREG_RECURSION_LIMIT_ERROR:
					$message = 'PHP regular expression limit reached
(pcre.recursion_limit)';
					break;
				case PREG_BAD_UTF8_ERROR:
					$message = 'Bad UTF8 passed to PCRE function';
					break;
				default:
					$message = 'Unknown PCRE error calling PCRE function';
			}

			throw new RuntimeException($message);
		}
	}

	/**
	 * Replace the matched tags.
	 *
	 * @param   array  &$matches  An array of matches (see
preg_match_all).
	 *
	 * @return  string
	 *
	 * @deprecated  4.0  No replacement.
	 */
	protected static function route(&$matches)
	{
		JLog::add(__METHOD__ . ' is deprecated, no replacement.',
JLog::WARNING, 'deprecated');

		$url   = $matches[1];
		$url   = str_replace('&amp;', '&', $url);
		$route = JRoute::_('index.php?' . $url);

		return 'href="' . $route;
	}
}
system/sef/sef.xml000064400000002040147357022250010147 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="system" method="upgrade">
	<name>plg_system_sef</name>
	<author>Joomla! Project</author>
	<creationDate>December 2007</creationDate>
	<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_SEF_XML_DESCRIPTION</description>
	<files>
		<filename plugin="sef">sef.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_system_sef.ini</language>
		<language
tag="en-GB">en-GB.plg_system_sef.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="domain"
					type="url"
					label="PLG_SEF_DOMAIN_LABEL"
					description="PLG_SEF_DOMAIN_DESCRIPTION"
					hint="https://www.example.com"
					filter="url"
					validate="url"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
system/sessiongc/sessiongc.php000064400000003311147357022250012600
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.sessiongc
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Session\MetadataManager;

/**
 * Garbage collection handler for session related data
 *
 * @since  3.8.6
 */
class PlgSystemSessionGc extends CMSPlugin
{
	/**
	 * Application object
	 *
	 * @var    CMSApplication
	 * @since  3.8.6
	 */
	protected $app;

	/**
	 * Database driver
	 *
	 * @var    JDatabaseDriver
	 * @since  3.8.6
	 */
	protected $db;

	/**
	 * Runs after the HTTP response has been sent to the client and performs
garbage collection tasks
	 *
	 * @return  void
	 *
	 * @since   3.8.6
	 */
	public function onAfterRespond()
	{
		$session = Factory::getSession();

		if ($this->params->get('enable_session_gc', 1))
		{
			$probability = $this->params->get('gc_probability', 1);
			$divisor     = $this->params->get('gc_divisor', 100);

			$random = $divisor * lcg_value();

			if ($probability > 0 && $random < $probability)
			{
				$session->gc();
			}
		}

		if ($this->app->get('session_handler', 'none')
!== 'database' &&
$this->params->get('enable_session_metadata_gc', 1))
		{
			$probability = $this->params->get('gc_probability', 1);
			$divisor     = $this->params->get('gc_divisor', 100);

			$random = $divisor * lcg_value();

			if ($probability > 0 && $random < $probability)
			{
				$metadataManager = new MetadataManager($this->app, $this->db);
				$metadataManager->deletePriorTo(time() - $session->getExpire());
			}
		}
	}
}
system/sessiongc/sessiongc.xml000064400000004340147357022250012614
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.8" type="plugin"
group="system" method="upgrade">
	<name>plg_system_sessiongc</name>
	<author>Joomla! Project</author>
	<creationDate>February 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.8.6</version>
	<description>PLG_SYSTEM_SESSIONGC_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="sessiongc">sessiongc.php</filename>
	</files>
	<languages folder="language">
		<language
tag="en-GB">en-GB/en-GB.plg_system_sessiongc.ini</language>
		<language
tag="en-GB">en-GB/en-GB.plg_system_sessiongc.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="enable_session_gc"
					type="radio"
					label="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_GC_LABEL"
					description="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_GC_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="uint"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="enable_session_metadata_gc"
					type="radio"
					label="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_METADATA_GC_LABEL"
					description="PLG_SYSTEM_SESSIONGC_ENABLE_SESSION_METADATA_GC_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					filter="uint"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="gc_probability"
					type="number"
					label="PLG_SYSTEM_SESSIONGC_GC_PROBABILITY_LABEL"
					description="PLG_SYSTEM_SESSIONGC_GC_PROBABILITY_DESC"
					filter="uint"
					validate="number"
					min="1"
					default="1"
					showon="enable_session_gc:1[OR]enable_session_metadata_gc:1"
				/>

				<field
					name="gc_divisor"
					type="number"
					label="PLG_SYSTEM_SESSIONGC_GC_DIVISOR_LABEL"
					description="PLG_SYSTEM_SESSIONGC_GC_DIVISOR_DESC"
					filter="uint"
					validate="number"
					min="1"
					default="100"
					showon="enable_session_gc:1[OR]enable_session_metadata_gc:1"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
system/stats/field/base.php000064400000001345147357022250011746
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Base field for the Stats Plugin.
 *
 * @since  3.5
 */
abstract class PlgSystemStatsFormFieldBase extends JFormField
{
	/**
	 * Get the layouts paths
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	protected function getLayoutPaths()
	{
		$template = JFactory::getApplication()->getTemplate();

		return array(
			JPATH_ADMINISTRATOR . '/templates/' . $template .
'/html/layouts/plugins/system/stats',
			dirname(__DIR__) . '/layouts',
			JPATH_SITE . '/layouts'
		);
	}
}
system/stats/field/data.php000064400000002240147357022250011740
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PlgSystemStatsFormFieldBase', __DIR__ .
'/base.php');

/**
 * Unique ID Field class for the Stats Plugin.
 *
 * @since  3.5
 */
class PlgSystemStatsFormFieldData extends PlgSystemStatsFormFieldBase
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $type = 'Data';

	/**
	 * Name of the layout being used to render the field
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $layout = 'field.data';

	/**
	 * Method to get the data to be passed to the layout for rendering.
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	protected function getLayoutData()
	{
		$data       = parent::getLayoutData();

		$dispatcher = JEventDispatcher::getInstance();
		JPluginHelper::importPlugin('system', 'stats');

		$result = $dispatcher->trigger('onGetStatsData',
array('stats.field.data'));

		$data['statsData'] = $result ? reset($result) : array();

		return $data;
	}
}
system/stats/field/uniqueid.php000064400000001334147357022250012655
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

JLoader::register('PlgSystemStatsFormFieldBase', __DIR__ .
'/base.php');

/**
 * Unique ID Field class for the Stats Plugin.
 *
 * @since  3.5
 */
class PlgSystemStatsFormFieldUniqueid extends PlgSystemStatsFormFieldBase
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $type = 'Uniqueid';

	/**
	 * Name of the layout being used to render the field
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $layout = 'field.uniqueid';
}
system/stats/layouts/field/data.php000064400000004332147357022250013444
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   string   $autocomplete    Autocomplete attribute for the field.
 * @var   boolean  $autofocus       Is autofocus enabled?
 * @var   string   $class           Classes for the input.
 * @var   string   $description     Description of the field.
 * @var   boolean  $disabled        Is this field disabled?
 * @var   string   $group           Group the field belongs to.
<fields> section in form XML.
 * @var   boolean  $hidden          Is this field hidden in the form?
 * @var   string   $hint            Placeholder for the field.
 * @var   string   $id              DOM id of the field.
 * @var   string   $label           Label of the field.
 * @var   string   $labelclass      Classes to apply to the label.
 * @var   boolean  $multiple        Does this field support multiple
values?
 * @var   string   $name            Name of the input field.
 * @var   string   $onchange        Onchange attribute for the field.
 * @var   string   $onclick         Onclick attribute for the field.
 * @var   string   $pattern         Pattern (Reg Ex) of value of the form
field.
 * @var   boolean  $readonly        Is this field read only?
 * @var   boolean  $repeat          Allows extensions to duplicate
elements.
 * @var   boolean  $required        Is this field required?
 * @var   integer  $size            Size attribute of the input.
 * @var   boolean  $spellcheck      Spellcheck state for the form field.
 * @var   string   $validate        Validation rules to apply.
 * @var   string   $value           Value attribute of the field.
 * @var   array    $options         Options available for this field.
 * @var   array    $statsData       Statistics that will be sent to the
stats server
 */

JHtml::_('jquery.framework');
?>
<a href="#" onclick="jQuery(this).next().toggle(200);
return false;"><?php echo
JText::_('PLG_SYSTEM_STATS_MSG_WHAT_DATA_WILL_BE_SENT');
?></a>
<?php
echo $field->render('stats', compact('statsData'));
system/stats/layouts/field/uniqueid.php000064400000004407147357022250014361
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   string   $autocomplete    Autocomplete attribute for the field.
 * @var   boolean  $autofocus       Is autofocus enabled?
 * @var   string   $class           Classes for the input.
 * @var   string   $description     Description of the field.
 * @var   boolean  $disabled        Is this field disabled?
 * @var   string   $group           Group the field belongs to.
<fields> section in form XML.
 * @var   boolean  $hidden          Is this field hidden in the form?
 * @var   string   $hint            Placeholder for the field.
 * @var   string   $id              DOM id of the field.
 * @var   string   $label           Label of the field.
 * @var   string   $labelclass      Classes to apply to the label.
 * @var   boolean  $multiple        Does this field support multiple
values?
 * @var   string   $name            Name of the input field.
 * @var   string   $onchange        Onchange attribute for the field.
 * @var   string   $onclick         Onclick attribute for the field.
 * @var   string   $pattern         Pattern (Reg Ex) of value of the form
field.
 * @var   boolean  $readonly        Is this field read only?
 * @var   boolean  $repeat          Allows extensions to duplicate
elements.
 * @var   boolean  $required        Is this field required?
 * @var   integer  $size            Size attribute of the input.
 * @var   boolean  $spellcheck      Spellcheck state for the form field.
 * @var   string   $validate        Validation rules to apply.
 * @var   string   $value           Value attribute of the field.
 * @var   array    $options         Options available for this field.
 */
?>
<input type="hidden" name="<?php echo $name;
?>" id="<?php echo $id; ?>" value="<?php
echo htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); ?>"
/>
<a class="btn"
onclick="document.getElementById('<?php echo $id;
?>').value='';Joomla.submitbutton('plugin.apply');">
	<span class="icon-refresh"></span> <?php echo
JText::_('PLG_SYSTEM_STATS_RESET_UNIQUE_ID'); ?>
</a>system/stats/layouts/message.php000064400000003014147357022250013070
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var  PlgSystemStats             $plugin        Plugin rendering this
layout
 * @var  \Joomla\Registry\Registry  $pluginParams  Plugin parameters
 * @var  array                      $statsData     Array containing the
data that will be sent to the stats server
 */
?>
<div class="alert alert-info js-pstats-alert"
style="display:none;">
	<button data-dismiss="alert" class="close"
type="button">×</button>
	<h2><?php echo
JText::_('PLG_SYSTEM_STATS_LABEL_MESSAGE_TITLE');
?></h2>
	<p>
		<?php echo
JText::_('PLG_SYSTEM_STATS_MSG_JOOMLA_WANTS_TO_SEND_DATA'); ?>
		<a href="#" class="js-pstats-btn-details
alert-link"><?php echo
JText::_('PLG_SYSTEM_STATS_MSG_WHAT_DATA_WILL_BE_SENT');
?></a>
	</p>
	<?php
		echo $plugin->render('stats',
compact('statsData'));
	?>
	<p><?php echo
JText::_('PLG_SYSTEM_STATS_MSG_ALLOW_SENDING_DATA');
?></p>
	<p class="actions">
		<a href="#" class="btn
js-pstats-btn-allow-always"><?php echo
JText::_('PLG_SYSTEM_STATS_BTN_SEND_ALWAYS'); ?></a>
		<a href="#" class="btn
js-pstats-btn-allow-once"><?php echo
JText::_('PLG_SYSTEM_STATS_BTN_SEND_NOW'); ?></a>
		<a href="#" class="btn
js-pstats-btn-allow-never"><?php echo
JText::_('PLG_SYSTEM_STATS_BTN_NEVER_SEND'); ?></a>
	</p>
</div>
system/stats/layouts/stats.php000064400000001546147357022250012612
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var  array  $statsData  Array containing the data that will be sent to
the stats server
 */

$versionFields = array('php_version', 'db_version',
'cms_version');
?>
<dl class="dl-horizontal js-pstats-data-details" 
style="display:none;">
	<?php foreach ($statsData as $key => $value) : ?>
		<dt><?php echo JText::_('PLG_SYSTEM_STATS_LABEL_' .
strtoupper($key)); ?></dt>
		<dd><?php echo in_array($key, $versionFields) ?
(preg_match('/\d+(?:\.\d+)+/', $value, $matches) ? $matches[0] :
$value) : $value; ?></dd>
	<?php endforeach; ?>
</dl>
system/stats/stats.php000064400000030705147357022250011111 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.stats
 *
 * @copyright   (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

// Uncomment the following line to enable debug mode for testing purposes.
Note: statistics will be sent on every page load
// define('PLG_SYSTEM_STATS_DEBUG', 1);

/**
 * Statistics system plugin. This sends anonymous data back to the Joomla!
Project about the
 * PHP, SQL, Joomla and OS versions
 *
 * @since  3.5
 */
class PlgSystemStats extends JPlugin
{
	/**
	 * Indicates sending statistics is always allowed.
	 *
	 * @var    integer
	 * @since  3.5
	 */
	const MODE_ALLOW_ALWAYS = 1;

	/**
	 * Indicates sending statistics is only allowed one time.
	 *
	 * @var    integer
	 * @since  3.5
	 */
	const MODE_ALLOW_ONCE = 2;

	/**
	 * Indicates sending statistics is never allowed.
	 *
	 * @var    integer
	 * @since  3.5
	 */
	const MODE_ALLOW_NEVER = 3;

	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 * @since  3.5
	 */
	protected $app;

	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 * @since  3.5
	 */
	protected $db;

	/**
	 * URL to send the statistics.
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $serverUrl =
'https://developer.joomla.org/stats/submit';

	/**
	 * Unique identifier for this site
	 *
	 * @var    string
	 * @since  3.5
	 */
	protected $uniqueId;

	/**
	 * Listener for the `onAfterInitialise` event
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	public function onAfterInitialise()
	{
		if (!$this->app->isClient('administrator') ||
!$this->isAllowedUser())
		{
			return;
		}

		if (!$this->isDebugEnabled() && !$this->isUpdateRequired())
		{
			return;
		}

		if (JUri::getInstance()->getVar('tmpl') ===
'component')
		{
			return;
		}

		// Load plugin language files only when needed (ex: they are not needed
in site client).
		$this->loadLanguage();

		JHtml::_('jquery.framework');
		JHtml::_('script', 'plg_system_stats/stats.js',
array('version' => 'auto', 'relative'
=> true));
	}

	/**
	 * User selected to always send data
	 *
	 * @return  void
	 *
	 * @since   3.5
	 *
	 * @throws  Exception         If user is not allowed.
	 * @throws  RuntimeException  If there is an error saving the params or
sending the data.
	 */
	public function onAjaxSendAlways()
	{
		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'),
403);
		}

		$this->params->set('mode', static::MODE_ALLOW_ALWAYS);

		if (!$this->saveParams())
		{
			throw new RuntimeException('Unable to save plugin settings',
500);
		}

		$this->sendStats();

		echo json_encode(array('sent' => 1));
	}

	/**
	 * User selected to never send data.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 *
	 * @throws  Exception         If user is not allowed.
	 * @throws  RuntimeException  If there is an error saving the params.
	 */
	public function onAjaxSendNever()
	{
		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'),
403);
		}

		$this->params->set('mode', static::MODE_ALLOW_NEVER);

		if (!$this->saveParams())
		{
			throw new RuntimeException('Unable to save plugin settings',
500);
		}

		echo json_encode(array('sent' => 0));
	}

	/**
	 * User selected to send data once.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 *
	 * @throws  Exception         If user is not allowed.
	 * @throws  RuntimeException  If there is an error saving the params or
sending the data.
	 */
	public function onAjaxSendOnce()
	{
		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'),
403);
		}

		$this->params->set('mode', static::MODE_ALLOW_ONCE);

		if (!$this->saveParams())
		{
			throw new RuntimeException('Unable to save plugin settings',
500);
		}

		$this->sendStats();

		echo json_encode(array('sent' => 1));
	}

	/**
	 * Send the stats to the server.
	 * On first load | on demand mode it will show a message asking users to
select mode.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 *
	 * @throws  Exception         If user is not allowed.
	 * @throws  RuntimeException  If there is an error saving the params or
sending the data.
	 */
	public function onAjaxSendStats()
	{
		if (!$this->isAllowedUser() || !$this->isAjaxRequest())
		{
			throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'),
403);
		}

		// User has not selected the mode. Show message.
		if ((int) $this->params->get('mode') !==
static::MODE_ALLOW_ALWAYS)
		{
			$data = array(
				'sent' => 0,
				'html' =>
$this->getRenderer('message')->render($this->getLayoutData())
			);

			echo json_encode($data);

			return;
		}

		if (!$this->saveParams())
		{
			throw new RuntimeException('Unable to save plugin settings',
500);
		}

		$this->sendStats();

		echo json_encode(array('sent' => 1));
	}

	/**
	 * Get the data through events
	 *
	 * @param   string  $context  Context where this will be called from
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	public function onGetStatsData($context)
	{
		return $this->getStatsData();
	}

	/**
	 * Debug a layout of this plugin
	 *
	 * @param   string  $layoutId  Layout identifier
	 * @param   array   $data      Optional data for the layout
	 *
	 * @return  string
	 *
	 * @since   3.5
	 */
	public function debug($layoutId, $data = array())
	{
		$data = array_merge($this->getLayoutData(), $data);

		return $this->getRenderer($layoutId)->debug($data);
	}

	/**
	 * Get the data for the layout
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	protected function getLayoutData()
	{
		return array(
			'plugin'       => $this,
			'pluginParams' => $this->params,
			'statsData'    => $this->getStatsData()
		);
	}

	/**
	 * Get the layout paths
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	protected function getLayoutPaths()
	{
		$template = JFactory::getApplication()->getTemplate();

		return array(
			JPATH_ADMINISTRATOR . '/templates/' . $template .
'/html/layouts/plugins/' . $this->_type . '/' .
$this->_name,
			__DIR__ . '/layouts',
		);
	}

	/**
	 * Get the plugin renderer
	 *
	 * @param   string  $layoutId  Layout identifier
	 *
	 * @return  JLayout
	 *
	 * @since   3.5
	 */
	protected function getRenderer($layoutId = 'default')
	{
		$renderer = new JLayoutFile($layoutId);

		$renderer->setIncludePaths($this->getLayoutPaths());

		return $renderer;
	}

	/**
	 * Get the data that will be sent to the stats server.
	 *
	 * @return  array
	 *
	 * @since   3.5
	 */
	private function getStatsData()
	{
		$data = array(
			'unique_id'   => $this->getUniqueId(),
			'php_version' => PHP_VERSION,
			'db_type'     => $this->db->name,
			'db_version'  => $this->db->getVersion(),
			'cms_version' => JVERSION,
			'server_os'   => php_uname('s') . ' ' .
php_uname('r')
		);

		// Check if we have a MariaDB version string and extract the proper
version from it
		if
(preg_match('/^(?:5\.5\.5-)?(mariadb-)?(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)/i',
$data['db_version'], $versionParts))
		{
			$data['db_version'] = $versionParts['major'] .
'.' . $versionParts['minor'] . '.' .
$versionParts['patch'];
		}

		return $data;
	}

	/**
	 * Get the unique id. Generates one if none is set.
	 *
	 * @return  integer
	 *
	 * @since   3.5
	 */
	private function getUniqueId()
	{
		if (null === $this->uniqueId)
		{
			$this->uniqueId = $this->params->get('unique_id',
hash('sha1', JUserHelper::genRandomPassword(28) . time()));
		}

		return $this->uniqueId;
	}

	/**
	 * Check if current user is allowed to send the data
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function isAllowedUser()
	{
		return JFactory::getUser()->authorise('core.admin');
	}

	/**
	 * Check if the debug is enabled
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function isDebugEnabled()
	{
		return defined('PLG_SYSTEM_STATS_DEBUG');
	}

	/**
	 * Check if last_run + interval > now
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function isUpdateRequired()
	{
		$last     = (int) $this->params->get('lastrun', 0);
		$interval = (int) $this->params->get('interval', 12);
		$mode     = (int) $this->params->get('mode', 0);

		if ($mode === static::MODE_ALLOW_NEVER)
		{
			return false;
		}

		// Never updated or debug enabled
		if (!$last || $this->isDebugEnabled())
		{
			return true;
		}

		return (abs(time() - $last) > $interval * 3600);
	}

	/**
	 * Check valid AJAX request
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function isAjaxRequest()
	{
		return
strtolower($this->app->input->server->get('HTTP_X_REQUESTED_WITH',
'')) === 'xmlhttprequest';
	}

	/**
	 * Render a layout of this plugin
	 *
	 * @param   string  $layoutId  Layout identifier
	 * @param   array   $data      Optional data for the layout
	 *
	 * @return  string
	 *
	 * @since   3.5
	 */
	public function render($layoutId, $data = array())
	{
		$data = array_merge($this->getLayoutData(), $data);

		return $this->getRenderer($layoutId)->render($data);
	}

	/**
	 * Save the plugin parameters
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 */
	private function saveParams()
	{
		// Update params
		$this->params->set('lastrun', time());
		$this->params->set('unique_id', $this->getUniqueId());
		$interval = (int) $this->params->get('interval', 12);
		$this->params->set('interval', $interval ?: 12);

		$query = $this->db->getQuery(true)
				->update($this->db->quoteName('#__extensions'))
				->set($this->db->quoteName('params') . ' =
' .
$this->db->quote($this->params->toString('JSON')))
				->where($this->db->quoteName('type') . ' =
' . $this->db->quote('plugin'))
				->where($this->db->quoteName('folder') . ' =
' . $this->db->quote('system'))
				->where($this->db->quoteName('element') . ' =
' . $this->db->quote('stats'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race
condition
			$this->db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue
execution
			return false;
		}

		try
		{
			// Update the plugin parameters
			$result = $this->db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$this->db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$this->db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		return $result;
	}

	/**
	 * Send the stats to the stats server
	 *
	 * @return  boolean
	 *
	 * @since   3.5
	 *
	 * @throws  RuntimeException  If there is an error sending the data.
	 */
	private function sendStats()
	{
		try
		{
			// Don't let the request take longer than 2 seconds to avoid page
timeout issues
			$response = JHttpFactory::getHttp()->post($this->serverUrl,
$this->getStatsData(), null, 2);
		}
		catch (UnexpectedValueException $e)
		{
			// There was an error sending stats. Should we do anything?
			throw new RuntimeException('Could not send site statistics to
remote server: ' . $e->getMessage(), 500);
		}
		catch (RuntimeException $e)
		{
			// There was an error connecting to the server or in the post request
			throw new RuntimeException('Could not connect to statistics server:
' . $e->getMessage(), 500);
		}
		catch (Exception $e)
		{
			// An unexpected error in processing; don't let this failure kill
the site
			throw new RuntimeException('Unexpected error connecting to
statistics server: ' . $e->getMessage(), 500);
		}

		if ($response->code !== 200)
		{
			$data = json_decode($response->body);

			throw new RuntimeException('Could not send site statistics to
remote server: ' . $data->message, $response->code);
		}

		return true;
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
	{
		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $client_id ? JPATH_ADMINISTRATOR .
'/cache' : $this->app->get('cache_path',
JPATH_SITE . '/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
system/stats/stats.xml000064400000003542147357022250011121 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin"
group="system" method="upgrade">
	<name>plg_system_stats</name>
	<author>Joomla! Project</author>
	<creationDate>November 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.5.0</version>
	<description>PLG_SYSTEM_STATS_XML_DESCRIPTION</description>
	<files>
		<folder>field</folder>
		<folder>layouts</folder>
		<filename plugin="stats">stats.php</filename>
	</files>
	<languages folder="language">
		<language
tag="en-GB">en-GB/en-GB.plg_system_stats.ini</language>
		<language
tag="en-GB">en-GB/en-GB.plg_system_stats.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="data"
					type="plgsystemstats.data"
					label=""
				/>

				<field
					name="unique_id"
					type="plgsystemstats.uniqueid"
					label="PLG_SYSTEM_STATS_UNIQUE_ID_LABEL"
					description="PLG_SYSTEM_STATS_UNIQUE_ID_DESC"
					size="10"
				/>

				<field
					name="interval"
					type="number"
					label="PLG_SYSTEM_STATS_INTERVAL_LABEL"
					description="PLG_SYSTEM_STATS_INTERVAL_DESC"
					filter="integer"
					default="12"
				/>

				<field
					name="mode"
					type="list"
					label="PLG_SYSTEM_STATS_MODE_LABEL"
					description="PLG_SYSTEM_STATS_MODE_DESC"
					default="1"
					>
					<option
value="1">PLG_SYSTEM_STATS_MODE_OPTION_ALWAYS_SEND</option>
					<option
value="2">PLG_SYSTEM_STATS_MODE_OPTION_ON_DEMAND</option>
					<option
value="3">PLG_SYSTEM_STATS_MODE_OPTION_NEVER_SEND</option>
				</field>

				<field
					name="lastrun"
					type="hidden"
					default="0"
					size="15"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
system/updatenotification/postinstall/updatecachetime.php000064400000002605147357022250020205
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.updatenotification
 *
 * @copyright   (C) 2016 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

/**
 * Checks if the com_installer config for the cache Hours are eq 0 and the
updatenotification Plugin is enabled
 *
 * @return  boolean
 *
 * @since   3.6.3
 */
function updatecachetime_postinstall_condition()
{
	$cacheTimeout = (int)
JComponentHelper::getComponent('com_installer')->params->get('cachetimeout',
6);

	// Check if cachetimeout is eq zero
	if ($cacheTimeout === 0 &&
JPluginHelper::isEnabled('system',
'updatenotification'))
	{
		return true;
	}

	return false;
}

/**
 * Sets the cachetimeout back to the default (6 hours)
 *
 * @return  void
 *
 * @since   3.6.3
 */
function updatecachetime_postinstall_action()
{
	$installer = JComponentHelper::getComponent('com_installer');

	// Sets the cachetimeout back to the default (6 hours)
	$installer->params->set('cachetimeout', 6);

	// Save the new parameters back to com_installer
	$table = JTable::getInstance('extension');
	$table->load($installer->id);
	$table->bind(array('params' =>
$installer->params->toString()));

	// Store the changes
	if (!$table->store())
	{
		// If there is an error show it to the admin
		JFactory::getApplication()->enqueueMessage($table->getError(),
'error');
	}
}
system/updatenotification/updatenotification.php000064400000026526147357022250016405
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.updatenotification
 *
 * @copyright   (C) 2015 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

// Uncomment the following line to enable debug mode (update notification
email sent every single time)
// define('PLG_SYSTEM_UPDATENOTIFICATION_DEBUG', 1);

/**
 * Joomla! Update Notification plugin
 *
 * Sends out an email to all Super Users or a predefined email address when
a new Joomla! version is available.
 *
 * This plugin is a direct adaptation of the corresponding plugin in Akeeba
Ltd's Admin Tools. The author has
 * consented to relicensing their plugin's code under GPLv2 or later
(the original version was licensed under
 * GPLv3 or later) to allow its inclusion in the Joomla! CMS.
 *
 * @since  3.5
 */
class PlgSystemUpdatenotification extends JPlugin
{
	/**
	 * Load plugin language files automatically
	 *
	 * @var    boolean
	 * @since  3.6.3
	 */
	protected $autoloadLanguage = true;

	/**
	 * The update check and notification email code is triggered after the
page has fully rendered.
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	public function onAfterRender()
	{
		// Get the timeout for Joomla! updates, as configured in
com_installer's component parameters
		$component = JComponentHelper::getComponent('com_installer');

		/** @var \Joomla\Registry\Registry $params */
		$params        = $component->params;
		$cache_timeout = (int) $params->get('cachetimeout', 6);
		$cache_timeout = 3600 * $cache_timeout;

		// Do we need to run? Compare the last run timestamp stored in the
plugin's options with the current
		// timestamp. If the difference is greater than the cache timeout we
shall not execute again.
		$now  = time();
		$last = (int) $this->params->get('lastrun', 0);

		if (!defined('PLG_SYSTEM_UPDATENOTIFICATION_DEBUG') &&
(abs($now - $last) < $cache_timeout))
		{
			return;
		}

		// Update last run status
		// If I have the time of the last run, I can update, otherwise insert
		$this->params->set('lastrun', $now);

		$db = JFactory::getDbo();
		$query = $db->getQuery(true)
					->update($db->qn('#__extensions'))
					->set($db->qn('params') . ' = ' .
$db->q($this->params->toString('JSON')))
					->where($db->qn('type') . ' = ' .
$db->q('plugin'))
					->where($db->qn('folder') . ' = ' .
$db->q('system'))
					->where($db->qn('element') . ' = ' .
$db->q('updatenotification'));

		try
		{
			// Lock the tables to prevent multiple plugin executions causing a race
condition
			$db->lockTable('#__extensions');
		}
		catch (Exception $e)
		{
			// If we can't lock the tables it's too risky to continue
execution
			return;
		}

		try
		{
			// Update the plugin parameters
			$result = $db->setQuery($query)->execute();

			$this->clearCacheGroups(array('com_plugins'), array(0, 1));
		}
		catch (Exception $exc)
		{
			// If we failed to execute
			$db->unlockTables();
			$result = false;
		}

		try
		{
			// Unlock the tables after writing
			$db->unlockTables();
		}
		catch (Exception $e)
		{
			// If we can't lock the tables assume we have somehow failed
			$result = false;
		}

		// Abort on failure
		if (!$result)
		{
			return;
		}

		// This is the extension ID for Joomla! itself
		$eid = 700;

		// Get any available updates
		$updater = JUpdater::getInstance();
		$results = $updater->findUpdates(array($eid), $cache_timeout);

		// If there are no updates our job is done. We need BOTH this check AND
the one below.
		if (!$results)
		{
			return;
		}

		// Unfortunately Joomla! MVC doesn't allow us to autoload classes
		JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_installer/models', 'InstallerModel');

		// Get the update model and retrieve the Joomla! core updates
		$model = JModelLegacy::getInstance('Update',
'InstallerModel');
		$model->setState('filter.extension_id', $eid);
		$updates = $model->getItems();

		// If there are no updates we don't have to notify anyone about
anything. This is NOT a duplicate check.
		if (empty($updates))
		{
			return;
		}

		// Get the available update
		$update = array_pop($updates);

		// Check the available version. If it's the same or less than the
installed version we have no updates to notify about.
		if (version_compare($update->version, JVERSION, 'le'))
		{
			return;
		}

		// If we're here, we have updates. First, get a link to the Joomla!
Update component.
		$baseURL  = JUri::base();
		$baseURL  = rtrim($baseURL, '/');
		$baseURL .= (substr($baseURL, -13) !== 'administrator') ?
'/administrator/' : '/';
		$baseURL .= 'index.php?option=com_joomlaupdate';
		$uri      = new JUri($baseURL);

		/**
		 * Some third party security solutions require a secret query parameter
to allow log in to the administrator
		 * backend of the site. The link generated above will be invalid and
could probably block the user out of their
		 * site, confusing them (they can't understand the third party
security solution is not part of Joomla! proper).
		 * So, we're calling the onBuildAdministratorLoginURL system plugin
event to let these third party solutions
		 * add any necessary secret query parameters to the URL. The plugins are
supposed to have a method with the
		 * signature:
		 *
		 * public function onBuildAdministratorLoginURL(JUri &$uri);
		 *
		 * The plugins should modify the $uri object directly and return null.
		 */

		JEventDispatcher::getInstance()->trigger('onBuildAdministratorLoginURL',
array(&$uri));

		// Let's find out the email addresses to notify
		$superUsers    = array();
		$specificEmail = $this->params->get('email',
'');

		if (!empty($specificEmail))
		{
			$superUsers = $this->getSuperUsers($specificEmail);
		}

		if (empty($superUsers))
		{
			$superUsers = $this->getSuperUsers();
		}

		if (empty($superUsers))
		{
			return;
		}

		/*
		 * Load the appropriate language. We try to load English (UK), the
current user's language and the forced
		 * language preference, in this order. This ensures that we'll never
end up with untranslated strings in the
		 * update email which would make Joomla! seem bad. So, please, if you
don't fully understand what the
		 * following code does DO NOT TOUCH IT. It makes the difference between a
hobbyist CMS and a professional
		 * solution! 
		 */
		$jLanguage = JFactory::getLanguage();
		$jLanguage->load('plg_system_updatenotification',
JPATH_ADMINISTRATOR, 'en-GB', true, true);
		$jLanguage->load('plg_system_updatenotification',
JPATH_ADMINISTRATOR, null, true, false);

		// Then try loading the preferred (forced) language
		$forcedLanguage = $this->params->get('language_override',
'');

		if (!empty($forcedLanguage))
		{
			$jLanguage->load('plg_system_updatenotification',
JPATH_ADMINISTRATOR, $forcedLanguage, true, false);
		}

		// Set up the email subject and body

		$email_subject =
JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT');
		$email_body    =
JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY');

		// Replace merge codes with their values
		$newVersion = $update->version;

		$jVersion       = new JVersion;
		$currentVersion = $jVersion->getShortVersion();

		$jConfig  = JFactory::getConfig();
		$sitename = $jConfig->get('sitename');
		$mailFrom = $jConfig->get('mailfrom');
		$fromName = $jConfig->get('fromname');

		$substitutions = array(
			'[NEWVERSION]'  => $newVersion,
			'[CURVERSION]'  => $currentVersion,
			'[SITENAME]'    => $sitename,
			'[URL]'         => JUri::base(),
			'[LINK]'        => $uri->toString(),
			'[RELEASENEWS]' =>
'https://www.joomla.org/announcements/release-news/',
			'\\n'           => "\n",
		);

		foreach ($substitutions as $k => $v)
		{
			$email_subject = str_replace($k, $v, $email_subject);
			$email_body    = str_replace($k, $v, $email_body);
		}

		// Send the emails to the Super Users
		foreach ($superUsers as $superUser)
		{
			$mailer = JFactory::getMailer();
			$mailer->setSender(array($mailFrom, $fromName));
			$mailer->addRecipient($superUser->email);
			$mailer->setSubject($email_subject);
			$mailer->setBody($email_body);
			$mailer->Send();
		}
	}

	/**
	 * Returns the Super Users email information. If you provide a comma
separated $email list
	 * we will check that these emails do belong to Super Users and that they
have not blocked
	 * system emails.
	 *
	 * @param   null|string  $email  A list of Super Users to email
	 *
	 * @return  array  The list of Super User emails
	 *
	 * @since   3.5
	 */
	private function getSuperUsers($email = null)
	{
		// Get a reference to the database object
		$db = JFactory::getDbo();

		// Convert the email list to an array
		if (!empty($email))
		{
			$temp   = explode(',', $email);
			$emails = array();

			foreach ($temp as $entry)
			{
				$entry    = trim($entry);
				$emails[] = $db->q($entry);
			}

			$emails = array_unique($emails);
		}
		else
		{
			$emails = array();
		}

		// Get a list of groups which have Super User privileges
		$ret = array();

		try
		{
			$rootId    = JTable::getInstance('Asset',
'JTable')->getRootId();
			$rules     = JAccess::getAssetRules($rootId)->getData();
			$rawGroups = $rules['core.admin']->getData();
			$groups    = array();

			if (empty($rawGroups))
			{
				return $ret;
			}

			foreach ($rawGroups as $g => $enabled)
			{
				if ($enabled)
				{
					$groups[] = $db->q($g);
				}
			}

			if (empty($groups))
			{
				return $ret;
			}
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		// Get the user IDs of users belonging to the SA groups
		try
		{
			$query = $db->getQuery(true)
						->select($db->qn('user_id'))
						->from($db->qn('#__user_usergroup_map'))
						->where($db->qn('group_id') . ' IN(' .
implode(',', $groups) . ')');
			$db->setQuery($query);
			$rawUserIDs = $db->loadColumn(0);

			if (empty($rawUserIDs))
			{
				return $ret;
			}

			$userIDs = array();

			foreach ($rawUserIDs as $id)
			{
				$userIDs[] = $db->q($id);
			}
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		// Get the user information for the Super Administrator users
		try
		{
			$query = $db->getQuery(true)
						->select(
							array(
								$db->qn('id'),
								$db->qn('username'),
								$db->qn('email'),
							)
						)->from($db->qn('#__users'))
						->where($db->qn('id') . ' IN(' .
implode(',', $userIDs) . ')')
						->where($db->qn('block') . ' = 0')
						->where($db->qn('sendEmail') . ' = ' .
$db->q('1'));

			if (!empty($emails))
			{
				$query->where('LOWER(' . $db->qn('email') .
') IN(' . implode(',',
array_map('strtolower', $emails)) . ')');
			}

			$db->setQuery($query);
			$ret = $db->loadObjectList();
		}
		catch (Exception $exc)
		{
			return $ret;
		}

		return $ret;
	}

	/**
	 * Clears cache groups. We use it to clear the plugins cache after we
update the last run timestamp.
	 *
	 * @param   array  $clearGroups   The cache groups to clean
	 * @param   array  $cacheClients  The cache clients (site, admin) to clean
	 *
	 * @return  void
	 *
	 * @since   3.5
	 */
	private function clearCacheGroups(array $clearGroups, array $cacheClients
= array(0, 1))
	{
		$conf = JFactory::getConfig();

		foreach ($clearGroups as $group)
		{
			foreach ($cacheClients as $client_id)
			{
				try
				{
					$options = array(
						'defaultgroup' => $group,
						'cachebase'    => $client_id ? JPATH_ADMINISTRATOR .
'/cache' :
							$conf->get('cache_path', JPATH_SITE .
'/cache')
					);

					$cache = JCache::getInstance('callback', $options);
					$cache->clean();
				}
				catch (Exception $e)
				{
					// Ignore it
				}
			}
		}
	}
}
system/updatenotification/updatenotification.xml000064400000003072147357022250016405
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.6" type="plugin"
group="system" method="upgrade">
	<name>plg_system_updatenotification</name>
	<author>Joomla! Project</author>
	<creationDate>May 2015</creationDate>
	<copyright>(C) 2015 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.5.0</version>
	<description>PLG_SYSTEM_UPDATENOTIFICATION_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="updatenotification">updatenotification.php</filename>
	</files>
	<languages folder="language">
		<language
tag="en-GB">en-GB.plg_system_updatenotification.ini</language>
		<language
tag="en-GB">en-GB.plg_system_updatenotification.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="email"
					type="text"
					label="PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_LBL"
					description="PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_DESC"
					default=""
					size="40"
				/>

				<field
					name="language_override"
					type="language"
					label="PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_LBL"
					description="PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_DESC"
					default=""
					client="administrator"
					>
					<option
value="">PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_NONE</option>
				</field>

				<field
					name="lastrun"
					type="hidden"
					default="0"
					size="15"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
twofactorauth/totp/postinstall/actions.php000064400000003525147357022250015165
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.totp
 *
 * @copyright   (C) 2013 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 *
 * This file contains the functions used by the com_postinstall code to
deliver
 * the necessary post-installation messages concerning the activation of
the
 * two-factor authentication code.
 */

/**
 * Checks if the plugin is enabled. If not it returns true, meaning that
the
 * message concerning two factor authentication should be displayed.
 *
 * @return  integer
 *
 * @since   3.2
 */
function twofactorauth_postinstall_condition()
{
	$db = JFactory::getDbo();

	$query = $db->getQuery(true)
		->select('*')
		->from($db->qn('#__extensions'))
		->where($db->qn('type') . ' = ' .
$db->q('plugin'))
		->where($db->qn('enabled') . ' = 1')
		->where($db->qn('folder') . ' = ' .
$db->q('twofactorauth'));
	$db->setQuery($query);
	$enabled_plugins = $db->loadObjectList();

	return count($enabled_plugins) === 0;
}

/**
 * Enables the two factor authentication plugin and redirects the user to
their
 * user profile page so that they can enable two factor authentication on
their
 * account.
 *
 * @return  void
 *
 * @since   3.2
 */
function twofactorauth_postinstall_action()
{
	// Enable the plugin
	$db = JFactory::getDbo();

	$query = $db->getQuery(true)
		->update($db->qn('#__extensions'))
		->set($db->qn('enabled') . ' = 1')
		->where($db->qn('type') . ' = ' .
$db->q('plugin'))
		->where($db->qn('folder') . ' = ' .
$db->q('twofactorauth'));
	$db->setQuery($query);
	$db->execute();

	// Clean cache.
	JFactory::getCache()->clean('com_plugins');

	// Redirect the user to their profile editor page
	$url = 'index.php?option=com_users&task=user.edit&id=' .
JFactory::getUser()->id;
	JFactory::getApplication()->redirect($url);
}
twofactorauth/totp/tmpl/form.php000064400000005756147357022250013100
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.totp.tmpl
 *
 * @copyright   (C) 2013 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Factory;

HTMLHelper::_('script',
'plg_twofactorauth_totp/qrcode.min.js', array('version'
=> 'auto', 'relative' => true));

$js = "
(function(document)
{
	document.addEventListener('DOMContentLoaded', function()
	{
		var qr = qrcode(0, 'H');
		qr.addData('" . $url . "');
		qr.make();

		document.getElementById('totp-qrcode').innerHTML =
qr.createImgTag(4);
	});
})(document);
";

Factory::getDocument()->addScriptDeclaration($js);
?>
<input type="hidden"
name="jform[twofactor][totp][key]" value="<?php echo
$secret ?>" />

<div class="well">
	<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_INTRO') ?>
</div>

<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_HEAD')
?>
	</legend>
	<p>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_TEXT')
?>
	</p>
	<ul>
		<li>
			<a href="<?php echo
JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_ITEM1_LINK') ?>"
target="_blank" rel="noopener noreferrer">
				<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_ITEM1')
?>
			</a>
		</li>
		<li>
			<a href="<?php echo
JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_ITEM2_LINK') ?>"
target="_blank" rel="noopener noreferrer">
				<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_ITEM2')
?>
			</a>
		</li>
	</ul>
	<div class="alert">
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP1_WARN')
?>
	</div>
</fieldset>

<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_HEAD')
?>
	</legend>

	<div class="span6">
		<p>
			<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_TEXT')
?>
		</p>
		<table class="table table-striped">
			<tr>
				<td>
					<?php echo
JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_ACCOUNT') ?>
				</td>
				<td>
					<?php echo $username ?>@<?php echo $hostname ?>
				</td>
			</tr>
			<tr>
				<td>
					<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_KEY')
?>
				</td>
				<td>
					<?php echo $secret ?>
				</td>
			</tr>
		</table>
	</div>

	<div class="span6">
		<p>
			<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_ALTTEXT')
?>
			<br />
			<div id="totp-qrcode"></div>
		</p>
	</div>

	<div class="clearfix"></div>

	<div class="alert alert-info">
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP2_RESET')
?>
	</div>
</fieldset>

<?php if ($new_totp): ?>
<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP3_HEAD')
?>
	</legend>
	<p>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_STEP3_TEXT')
?>
	</p>
	<div class="control-group">
		<label class="control-label"
for="totpsecuritycode">
			<?php echo
JText::_('PLG_TWOFACTORAUTH_TOTP_STEP3_SECURITYCODE') ?>
		</label>
		<div class="controls">
			<input type="text" class="input-small"
name="jform[twofactor][totp][securitycode]"
id="totpsecuritycode" autocomplete="0">
		</div>
	</div>
</fieldset>
<?php endif; ?>
twofactorauth/totp/totp.php000064400000017041147357022250012135
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.totp
 *
 * @copyright   (C) 2013 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! Two Factor Authentication using Google Authenticator TOTP Plugin
 *
 * @since  3.2
 */
class PlgTwofactorauthTotp extends JPlugin
{
	/**
	 * Affects constructor behavior. If true, language files will be loaded
automatically.
	 *
	 * @var    boolean
	 * @since  3.2
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method name
	 *
	 * @var    string
	 * @since  3.2
	 */
	protected $methodName = 'totp';

	/**
	 * This method returns the identification object for this two factor
	 * authentication plugin.
	 *
	 * @return  stdClass  An object with public properties method and title
	 *
	 * @since   3.2
	 */
	public function onUserTwofactorIdentify()
	{
		$section = (int) $this->params->get('section', 3);

		$current_section = 0;

		try
		{
			$app = JFactory::getApplication();

			if ($app->isClient('administrator'))
			{
				$current_section = 2;
			}
			elseif ($app->isClient('site'))
			{
				$current_section = 1;
			}
		}
		catch (Exception $exc)
		{
			$current_section = 0;
		}

		if (!($current_section & $section))
		{
			return false;
		}

		return (object) array(
			'method' => $this->methodName,
			'title'  =>
JText::_('PLG_TWOFACTORAUTH_TOTP_METHOD_TITLE')
		);
	}

	/**
	 * Shows the configuration page for this two factor authentication method.
	 *
	 * @param   object   $otpConfig  The two factor auth configuration object
	 * @param   integer  $userId     The numeric user ID of the user whose
form we'll display
	 *
	 * @return  boolean|string  False if the method is not ours, the HTML of
the configuration page otherwise
	 *
	 * @see     UsersModelUser::getOtpConfig
	 * @since   3.2
	 */
	public function onUserTwofactorShowConfiguration($otpConfig, $userId =
null)
	{
		// Create a new TOTP class with Google Authenticator compatible settings
		$totp = new FOFEncryptTotp(30, 6, 10);

		if ($otpConfig->method === $this->methodName)
		{
			// This method is already activated. Reuse the same secret key.
			$secret = $otpConfig->config['code'];
		}
		else
		{
			// This methods is not activated yet. Create a new secret key.
			$secret = $totp->generateSecret();
		}

		// These are used by Google Authenticator to tell accounts apart
		$username = JFactory::getUser($userId)->username;
		$hostname = JUri::getInstance()->getHost();

		// This is the URL to the QR code for Google Authenticator
		$url = sprintf("otpauth://totp/%s@%s?secret=%s", $username,
$hostname, $secret);

		// Is this a new TOTP setup? If so, we'll have to show the code
validation field.
		$new_totp = $otpConfig->method !== 'totp';

		// Start output buffering
		@ob_start();

		// Include the form.php from a template override. If none is found use
the default.
		$path =
FOFPlatform::getInstance()->getTemplateOverridePath('plg_twofactorauth_totp',
true);

		JLoader::import('joomla.filesystem.file');

		if (JFile::exists($path . '/form.php'))
		{
			include_once $path . '/form.php';
		}
		else
		{
			include_once __DIR__ . '/tmpl/form.php';
		}

		// Stop output buffering and get the form contents
		$html = @ob_get_clean();

		// Return the form contents
		return array(
			'method' => $this->methodName,
			'form'   => $html
		);
	}

	/**
	 * The save handler of the two factor configuration method's
configuration
	 * page.
	 *
	 * @param   string  $method  The two factor auth method for which
we'll show the config page
	 *
	 * @return  boolean|stdClass  False if the method doesn't match or we
have an error, OTP config object if it succeeds
	 *
	 * @see     UsersModelUser::setOtpConfig
	 * @since   3.2
	 */
	public function onUserTwofactorApplyConfiguration($method)
	{
		if ($method !== $this->methodName)
		{
			return false;
		}

		// Get a reference to the input data object
		$input = JFactory::getApplication()->input;

		// Load raw data
		$rawData = $input->get('jform', array(), 'array');

		if (!isset($rawData['twofactor']['totp']))
		{
			return false;
		}

		$data = $rawData['twofactor']['totp'];

		// Warn if the securitycode is empty
		if (array_key_exists('securitycode', $data) &&
empty($data['securitycode']))
		{
			try
			{
				$app = JFactory::getApplication();
				$app->enqueueMessage(JText::_('PLG_TWOFACTORAUTH_TOTP_ERR_VALIDATIONFAILED'),
'error');
			}
			catch (Exception $exc)
			{
				// This only happens when we are in a CLI application. We cannot
				// enqueue a message, so just do nothing.
			}

			return false;
		}

		// Create a new TOTP class with Google Authenticator compatible settings
		$totp = new FOFEncryptTotp(30, 6, 10);

		// Check the security code entered by the user (exact time slot match)
		$code = $totp->getCode($data['key']);
		$check = $code === $data['securitycode'];

		/*
		 * If the check fails, test the previous 30 second slot. This allow the
		 * user to enter the security code when it's becoming red in Google
		 * Authenticator app (reaching the end of its 30 second lifetime)
		 */
		if (!$check)
		{
			$time = time() - 30;
			$code = $totp->getCode($data['key'], $time);
			$check = $code === $data['securitycode'];
		}

		/*
		 * If the check fails, test the next 30 second slot. This allows some
		 * time drift between the authentication device and the server
		 */
		if (!$check)
		{
			$time = time() + 30;
			$code = $totp->getCode($data['key'], $time);
			$check = $code === $data['securitycode'];
		}

		if (!$check)
		{
			// Check failed. Do not change two factor authentication settings.
			return false;
		}

		// Check succeeded; return an OTP configuration object
		$otpConfig = (object) array(
			'method'   => 'totp',
			'config'   => array(
				'code' => $data['key']
			),
			'otep'     => array()
		);

		return $otpConfig;
	}

	/**
	 * This method should handle any two factor authentication and report back
	 * to the subject.
	 *
	 * @param   array  $credentials  Array holding the user credentials
	 * @param   array  $options      Array of extra options
	 *
	 * @return  boolean  True if the user is authorised with this two-factor
authentication method
	 *
	 * @since   3.2
	 */
	public function onUserTwofactorAuthenticate($credentials, $options)
	{
		// Get the OTP configuration object
		$otpConfig = $options['otp_config'];

		// Make sure it's an object
		if (empty($otpConfig) || !is_object($otpConfig))
		{
			return false;
		}

		// Check if we have the correct method
		if ($otpConfig->method !== $this->methodName)
		{
			return false;
		}

		// Check if there is a security code
		if (empty($credentials['secretkey']))
		{
			return false;
		}

		// Create a new TOTP class with Google Authenticator compatible settings
		$totp = new FOFEncryptTotp(30, 6, 10);

		// Check the code
		$code = $totp->getCode($otpConfig->config['code']);
		$check = $code === $credentials['secretkey'];

		/*
		 * If the check fails, test the previous 30 second slot. This allow the
		 * user to enter the security code when it's becoming red in Google
		 * Authenticator app (reaching the end of its 30 second lifetime)
		 */
		if (!$check)
		{
			$time = time() - 30;
			$code = $totp->getCode($otpConfig->config['code'],
$time);
			$check = $code === $credentials['secretkey'];
		}

		/*
		 * If the check fails, test the next 30 second slot. This allows some
		 * time drift between the authentication device and the server
		 */
		if (!$check)
		{
			$time = time() + 30;
			$code = $totp->getCode($otpConfig->config['code'],
$time);
			$check = $code === $credentials['secretkey'];
		}

		return $check;
	}
}
twofactorauth/totp/totp.xml000064400000002557147357022250012154
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="twofactorauth" method="upgrade">
	<name>plg_twofactorauth_totp</name>
	<author>Joomla! Project</author>
	<creationDate>August 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.2.0</version>
	<description>PLG_TWOFACTORAUTH_TOTP_XML_DESCRIPTION</description>
	<files>
		<filename plugin="totp">totp.php</filename>
		<folder>postinstall</folder>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_twofactorauth_totp.ini</language>
		<language
tag="en-GB">en-GB.plg_twofactorauth_totp.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="section"
					type="radio"
					label="PLG_TWOFACTORAUTH_TOTP_SECTION_LABEL"
					description="PLG_TWOFACTORAUTH_TOTP_SECTION_DESC"
					default="3"
					filter="integer"
					class="btn-group"
					>
					<option
value="1">PLG_TWOFACTORAUTH_TOTP_SECTION_SITE</option>
					<option
value="2">PLG_TWOFACTORAUTH_TOTP_SECTION_ADMIN</option>
					<option
value="3">PLG_TWOFACTORAUTH_TOTP_SECTION_BOTH</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
twofactorauth/yubikey/tmpl/form.php000064400000002145147357022250013560
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.yubikey.tmpl
 *
 * @copyright   (C) 2013 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;
?>
<div class="well">
	<?php echo JText::_('PLG_TWOFACTORAUTH_YUBIKEY_INTRO') ?>
</div>

<?php if ($new_totp): ?>
<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_YUBIKEY_STEP1_HEAD')
?>
	</legend>

	<p>
		<?php echo JText::_('PLG_TWOFACTORAUTH_YUBIKEY_STEP1_TEXT')
?>
	</p>

	<div class="control-group">
		<label class="control-label"
for="yubikeysecuritycode">
			<?php echo
JText::_('PLG_TWOFACTORAUTH_YUBIKEY_SECURITYCODE') ?>
		</label>
		<div class="controls">
			<input type="text" class="input-medium"
name="jform[twofactor][yubikey][securitycode]"
id="yubikeysecuritycode" autocomplete="0">
		</div>
	</div>
</fieldset>
<?php else: ?>
<fieldset>
	<legend>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_RESET_HEAD')
?>
	</legend>

	<p>
		<?php echo JText::_('PLG_TWOFACTORAUTH_TOTP_RESET_TEXT')
?>
	</p>
</fieldset>
<?php endif; ?>
twofactorauth/yubikey/yubikey.php000064400000020512147357022250013320
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Twofactorauth.yubikey
 *
 * @copyright   (C) 2013 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * Joomla! Two Factor Authentication using Yubikey Plugin
 *
 * @since  3.2
 */
class PlgTwofactorauthYubikey extends JPlugin
{
	/**
	 * Affects constructor behavior. If true, language files will be loaded
automatically.
	 *
	 * @var    boolean
	 * @since  3.2
	 */
	protected $autoloadLanguage = true;

	/**
	 * Method name
	 *
	 * @var    string
	 * @since  3.2
	 */
	protected $methodName = 'yubikey';

	/**
	 * This method returns the identification object for this two factor
	 * authentication plugin.
	 *
	 * @return  stdClass  An object with public properties method and title
	 *
	 * @since   3.2
	 */
	public function onUserTwofactorIdentify()
	{
		$section         = (int) $this->params->get('section',
3);
		$current_section = 0;

		try
		{
			$app = JFactory::getApplication();

			if ($app->isClient('administrator'))
			{
				$current_section = 2;
			}
			elseif ($app->isClient('site'))
			{
				$current_section = 1;
			}
		}
		catch (Exception $exc)
		{
			$current_section = 0;
		}

		if (!($current_section & $section))
		{
			return false;
		}

		return (object) array(
			'method' => $this->methodName,
			'title'  =>
JText::_('PLG_TWOFACTORAUTH_YUBIKEY_METHOD_TITLE'),
		);
	}

	/**
	 * Shows the configuration page for this two factor authentication method.
	 *
	 * @param   object   $otpConfig  The two factor auth configuration object
	 * @param   integer  $userId     The numeric user ID of the user whose
form we'll display
	 *
	 * @return  boolean|string  False if the method is not ours, the HTML of
the configuration page otherwise
	 *
	 * @see     UsersModelUser::getOtpConfig
	 * @since   3.2
	 */
	public function onUserTwofactorShowConfiguration($otpConfig, $userId =
null)
	{
		if ($otpConfig->method === $this->methodName)
		{
			// This method is already activated. Reuse the same Yubikey ID.
			$yubikey = $otpConfig->config['yubikey'];
		}
		else
		{
			// This methods is not activated yet. We'll need a Yubikey TOTP to
setup this Yubikey.
			$yubikey = '';
		}

		// Is this a new TOTP setup? If so, we'll have to show the code
validation field.
		$new_totp    = $otpConfig->method !== $this->methodName;

		// Start output buffering
		@ob_start();

		// Include the form.php from a template override. If none is found use
the default.
		$path =
FOFPlatform::getInstance()->getTemplateOverridePath('plg_twofactorauth_yubikey',
true);

		JLoader::import('joomla.filesystem.file');

		if (JFile::exists($path . '/form.php'))
		{
			include_once $path . '/form.php';
		}
		else
		{
			include_once __DIR__ . '/tmpl/form.php';
		}

		// Stop output buffering and get the form contents
		$html = @ob_get_clean();

		// Return the form contents
		return array(
			'method' => $this->methodName,
			'form'   => $html,
		);
	}

	/**
	 * The save handler of the two factor configuration method's
configuration
	 * page.
	 *
	 * @param   string  $method  The two factor auth method for which
we'll show the config page
	 *
	 * @return  boolean|stdClass  False if the method doesn't match or we
have an error, OTP config object if it succeeds
	 *
	 * @see     UsersModelUser::setOtpConfig
	 * @since   3.2
	 */
	public function onUserTwofactorApplyConfiguration($method)
	{
		if ($method !== $this->methodName)
		{
			return false;
		}

		// Get a reference to the input data object
		$input = JFactory::getApplication()->input;

		// Load raw data
		$rawData = $input->get('jform', array(), 'array');

		if (!isset($rawData['twofactor']['yubikey']))
		{
			return false;
		}

		$data = $rawData['twofactor']['yubikey'];

		// Warn if the securitycode is empty
		if (array_key_exists('securitycode', $data) &&
empty($data['securitycode']))
		{
			try
			{
				JFactory::getApplication()->enqueueMessage(JText::_('PLG_TWOFACTORAUTH_YUBIKEY_ERR_VALIDATIONFAILED'),
'error');
			}
			catch (Exception $exc)
			{
				// This only happens when we are in a CLI application. We cannot
				// enqueue a message, so just do nothing.
			}

			return false;
		}

		// Validate the Yubikey OTP
		$check = $this->validateYubikeyOtp($data['securitycode']);

		if (!$check)
		{
			JFactory::getApplication()->enqueueMessage(JText::_('PLG_TWOFACTORAUTH_YUBIKEY_ERR_VALIDATIONFAILED'),
'error');

			// Check failed. Do not change two factor authentication settings.
			return false;
		}

		// Remove the last 32 digits and store the rest in the user configuration
parameters
		$yubikey      = substr($data['securitycode'], 0, -32);

		// Check succeeded; return an OTP configuration object
		$otpConfig    = (object) array(
			'method'  => $this->methodName,
			'config'  => array(
				'yubikey' => $yubikey
			),
			'otep'    => array()
		);

		return $otpConfig;
	}

	/**
	 * This method should handle any two factor authentication and report back
	 * to the subject.
	 *
	 * @param   array  $credentials  Array holding the user credentials
	 * @param   array  $options      Array of extra options
	 *
	 * @return  boolean  True if the user is authorised with this two-factor
authentication method
	 *
	 * @since   3.2
	 */
	public function onUserTwofactorAuthenticate($credentials, $options)
	{
		// Get the OTP configuration object
		$otpConfig = $options['otp_config'];

		// Make sure it's an object
		if (empty($otpConfig) || !is_object($otpConfig))
		{
			return false;
		}

		// Check if we have the correct method
		if ($otpConfig->method !== $this->methodName)
		{
			return false;
		}

		// Check if there is a security code
		if (empty($credentials['secretkey']))
		{
			return false;
		}

		// Check if the Yubikey starts with the configured Yubikey user string
		$yubikey_valid = $otpConfig->config['yubikey'];
		$yubikey       = substr($credentials['secretkey'], 0, -32);

		$check = $yubikey === $yubikey_valid;

		if ($check)
		{
			$check =
$this->validateYubikeyOtp($credentials['secretkey']);
		}

		return $check;
	}

	/**
	 * Validates a Yubikey OTP against the Yubikey servers
	 *
	 * @param   string  $otp  The OTP generated by your Yubikey
	 *
	 * @return  boolean  True if it's a valid OTP
	 *
	 * @since   3.2
	 */
	public function validateYubikeyOtp($otp)
	{
		$server_queue = array(
			'api.yubico.com',
			'api2.yubico.com',
			'api3.yubico.com',
			'api4.yubico.com',
			'api5.yubico.com',
		);

		shuffle($server_queue);

		$gotResponse = false;
		$check       = false;

		$token = JSession::getFormToken();
		$nonce = md5($token . uniqid(mt_rand()));

		while (!$gotResponse && !empty($server_queue))
		{
			$server = array_shift($server_queue);
			$uri    = new JUri('https://' . $server .
'/wsapi/2.0/verify');

			// I don't see where this ID is used?
			$uri->setVar('id', 1);

			// The OTP we read from the user
			$uri->setVar('otp', $otp);

			// This prevents a REPLAYED_OTP status of the token doesn't change
			// after a user submits an invalid OTP
			$uri->setVar('nonce', $nonce);

			// Minimum service level required: 50% (at least 50% of the YubiCloud
			// servers must reply positively for the OTP to validate)
			$uri->setVar('sl', 50);

			// Timeou waiting for YubiCloud servers to reply: 5 seconds.
			$uri->setVar('timeout', 5);

			try
			{
				$http     = JHttpFactory::getHttp();
				$response = $http->get($uri->toString(), null, 6);

				if (!empty($response))
				{
					$gotResponse = true;
				}
				else
				{
					continue;
				}
			}
			catch (Exception $exc)
			{
				// No response, continue with the next server
				continue;
			}
		}

		// No server replied; we can't validate this OTP
		if (!$gotResponse)
		{
			return false;
		}

		// Parse response
		$lines = explode("\n", $response->body);
		$data  = array();

		foreach ($lines as $line)
		{
			$line  = trim($line);
			$parts = explode('=', $line, 2);

			if (count($parts) < 2)
			{
				continue;
			}

			$data[$parts[0]] = $parts[1];
		}

		// Validate the response - We need an OK message reply
		if ($data['status'] !== 'OK')
		{
			return false;
		}

		// Validate the response - We need a confidence level over 50%
		if ($data['sl'] < 50)
		{
			return false;
		}

		// Validate the response - The OTP must match
		if ($data['otp'] !== $otp)
		{
			return false;
		}

		// Validate the response - The token must match
		if ($data['nonce'] !== $nonce)
		{
			return false;
		}

		return true;
	}
}
twofactorauth/yubikey/yubikey.xml000064400000002564147357022250013340
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="twofactorauth" method="upgrade">
	<name>plg_twofactorauth_yubikey</name>
	<author>Joomla! Project</author>
	<creationDate>September 2013</creationDate>
	<copyright>(C) 2013 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.2.0</version>
	<description>PLG_TWOFACTORAUTH_YUBIKEY_XML_DESCRIPTION</description>
	<files>
		<filename plugin="yubikey">yubikey.php</filename>
		<folder>tmpl</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_twofactorauth_yubikey.ini</language>
		<language
tag="en-GB">en-GB.plg_twofactorauth_yubikey.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="section"
					type="radio"
					label="PLG_TWOFACTORAUTH_YUBIKEY_SECTION_LABEL"
					description="PLG_TWOFACTORAUTH_YUBIKEY_SECTION_DESC"
					default="3"
					filter="integer"
					class="btn-group"
					>
					<option
value="1">PLG_TWOFACTORAUTH_YUBIKEY_SECTION_SITE</option>
					<option
value="2">PLG_TWOFACTORAUTH_YUBIKEY_SECTION_ADMIN</option>
					<option
value="3">PLG_TWOFACTORAUTH_YUBIKEY_SECTION_BOTH</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
user/contactcreator/contactcreator.php000064400000010207147357022250014270
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.contactcreator
 *
 * @copyright   (C) 2010 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Table\Table;
use Joomla\String\StringHelper;

/**
 * Class for Contact Creator
 *
 * A tool to automatically create and synchronise contacts with a user
 *
 * @since  1.6
 */
class PlgUserContactCreator extends JPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Utility method to act on a user after it has been saved.
	 *
	 * This method creates a contact for the saved user
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isnew    True if a new user is stored.
	 * @param   boolean  $success  True if user was successfully stored in the
database.
	 * @param   string   $msg      Message.
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		// If the user wasn't stored we don't resync
		if (!$success)
		{
			return false;
		}

		// If the user isn't new we don't sync
		if (!$isnew)
		{
			return false;
		}

		// Ensure the user id is really an int
		$user_id = (int) $user['id'];

		// If the user id appears invalid then bail out just in case
		if (empty($user_id))
		{
			return false;
		}

		$categoryId = $this->params->get('category', 0);

		if (empty($categoryId))
		{
			JError::raiseWarning('',
Text::_('PLG_CONTACTCREATOR_ERR_NO_CATEGORY'));

			return false;
		}

		if ($contact = $this->getContactTable())
		{
			/**
			 * Try to pre-load a contact for this user. Apparently only possible if
other plugin creates it
			 * Note: $user_id is cleaned above
			 */
			if (!$contact->load(array('user_id' => (int) $user_id)))
			{
				$contact->published =
$this->params->get('autopublish', 0);
			}

			$contact->name     = $user['name'];
			$contact->user_id  = $user_id;
			$contact->email_to = $user['email'];
			$contact->catid    = $categoryId;
			$contact->access   = (int)
Factory::getConfig()->get('access');
			$contact->language = '*';
			$contact->generateAlias();

			// Check if the contact already exists to generate new name & alias
if required
			if ($contact->id == 0)
			{
				list($name, $alias) =
$this->generateAliasAndName($contact->alias, $contact->name,
$categoryId);

				$contact->name  = $name;
				$contact->alias = $alias;
			}

			$autowebpage = $this->params->get('autowebpage',
'');

			if (!empty($autowebpage))
			{
				// Search terms
				$search_array = array('[name]', '[username]',
'[userid]', '[email]');

				// Replacement terms, urlencoded
				$replace_array = array_map('urlencode',
array($user['name'], $user['username'],
$user['id'], $user['email']));

				// Now replace it in together
				$contact->webpage = str_replace($search_array, $replace_array,
$autowebpage);
			}

			if ($contact->check() && $contact->store())
			{
				return true;
			}
		}

		JError::raiseWarning('',
Text::_('PLG_CONTACTCREATOR_ERR_FAILED_CREATING_CONTACT'));

		return false;
	}

	/**
	 * Method to change the name & alias if alias is already in use
	 *
	 * @param   string   $alias       The alias.
	 * @param   string   $name        The name.
	 * @param   integer  $categoryId  Category identifier
	 *
	 * @return  array  Contains the modified title and alias.
	 *
	 * @since   3.2.3
	 */
	protected function generateAliasAndName($alias, $name, $categoryId)
	{
		$table = $this->getContactTable();

		while ($table->load(array('alias' => $alias,
'catid' => $categoryId)))
		{
			if ($name === $table->name)
			{
				$name = StringHelper::increment($name);
			}

			$alias = StringHelper::increment($alias, 'dash');
		}

		return array($name, $alias);
	}

	/**
	 * Get an instance of the contact table
	 *
	 * @return  ContactTableContact
	 *
	 * @since   3.2.3
	 */
	protected function getContactTable()
	{
		Table::addIncludePath(JPATH_ADMINISTRATOR .
'/components/com_contact/tables');

		return Table::getInstance('contact', 'ContactTable');
	}
}
user/contactcreator/contactcreator.xml000064400000003153147357022250014303
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="user" method="upgrade">
	<name>plg_user_contactcreator</name>
	<author>Joomla! Project</author>
	<creationDate>August 2009</creationDate>
	<copyright>(C) 2009 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_CONTACTCREATOR_XML_DESCRIPTION</description>
	<files>
		<filename
plugin="contactcreator">contactcreator.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_user_contactcreator.ini</language>
		<language
tag="en-GB">en-GB.plg_user_contactcreator.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="autowebpage"
					type="text"
					label="PLG_CONTACTCREATOR_FIELD_AUTOMATIC_WEBPAGE_LABEL"
					description="PLG_CONTACTCREATOR_FIELD_AUTOMATIC_WEBPAGE_DESC"
					size="40"
				/>

				<field
					name="category"
					type="category"
					label="JCATEGORY"
					description="PLG_CONTACTCREATOR_FIELD_CATEGORY_DESC"
					extension="com_contact"
					filter="integer"
				/>

				<field
					name="autopublish"
					type="radio"
					label="PLG_CONTACTCREATOR_FIELD_AUTOPUBLISH_LABEL"
					description="PLG_CONTACTCREATOR_FIELD_AUTOPUBLISH_DESC"
					class="btn-group btn-group-yesno"
					default="0"
					filter="integer"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
user/joomla/joomla.php000064400000024417147357022250011014 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.joomla
 *
 * @copyright   (C) 2006 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\User\User;
use Joomla\CMS\User\UserHelper;
use Joomla\Registry\Registry;

/**
 * Joomla User plugin
 *
 * @since  1.5
 */
class PlgUserJoomla extends JPlugin
{
	/**
	 * Application object
	 *
	 * @var    JApplicationCms
	 * @since  3.2
	 */
	protected $app;

	/**
	 * Database object
	 *
	 * @var    JDatabaseDriver
	 * @since  3.2
	 */
	protected $db;

	/**
	 * Set as required the passwords fields when mail to user is set to No
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.2
	 */
	public function onContentPrepareForm($form, $data)
	{
		// Check we are manipulating a valid user form before modifying it.
		$name = $form->getName();

		if ($name === 'com_users.user')
		{
			// In case there is a validation error (like duplicated user), $data is
an empty array on save.
			// After returning from error, $data is an array but populated
			if (!$data)
			{
				$data = JFactory::getApplication()->input->get('jform',
array(), 'array');
			}

			if (is_array($data))
			{
				$data = (object) $data;
			}

			// Passwords fields are required when mail to user is set to No
			if (empty($data->id) &&
!$this->params->get('mail_to_user', 1))
			{
				$form->setFieldAttribute('password', 'required',
'true');
				$form->setFieldAttribute('password2',
'required', 'true');
			}
		}

		return true;
	}

	/**
	 * Remove all sessions for the user name
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the
database
	 * @param   string   $msg      Message
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		$query = $this->db->getQuery(true)
			->delete($this->db->quoteName('#__session'))
			->where($this->db->quoteName('userid') . ' =
' . (int) $user['id']);

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		$query = $this->db->getQuery(true)
			->delete($this->db->quoteName('#__messages'))
			->where($this->db->quoteName('user_id_from') . '
= ' . (int) $user['id']);

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (JDatabaseExceptionExecuting $e)
		{
			return false;
		}

		return true;
	}

	/**
	 * Utility method to act on a user after it has been saved.
	 *
	 * This method sends a registration email to new users created in the
backend.
	 *
	 * @param   array    $user     Holds the new user data.
	 * @param   boolean  $isnew    True if a new user is stored.
	 * @param   boolean  $success  True if user was successfully stored in the
database.
	 * @param   string   $msg      Message.
	 *
	 * @return  void
	 *
	 * @since   1.6
	 */
	public function onUserAfterSave($user, $isnew, $success, $msg)
	{
		$mail_to_user = $this->params->get('mail_to_user', 1);

		if (!$isnew || !$mail_to_user)
		{
			return;
		}

		// TODO: Suck in the frontend registration emails here as well. Job for a
rainy day.
		// The method check here ensures that if running as a CLI Application we
don't get any errors
		if (method_exists($this->app, 'isClient') &&
!$this->app->isClient('administrator'))
		{
			return;
		}

		// Check if we have a sensible from email address, if not bail out as
mail would not be sent anyway
		if (strpos($this->app->get('mailfrom'), '@')
=== false)
		{
			$this->app->enqueueMessage(Text::_('JERROR_SENDING_EMAIL'),
'warning');

			return;
		}

		$lang = Factory::getLanguage();
		$defaultLocale = $lang->getTag();

		/**
		 * Look for user language. Priority:
		 * 	1. User frontend language
		 * 	2. User backend language
		 */
		$userParams = new Registry($user['params']);
		$userLocale = $userParams->get('language',
$userParams->get('admin_language', $defaultLocale));

		if ($userLocale !== $defaultLocale)
		{
			$lang->setLanguage($userLocale);
		}

		$lang->load('plg_user_joomla', JPATH_ADMINISTRATOR);

		// Compute the mail subject.
		$emailSubject = Text::sprintf(
			'PLG_USER_JOOMLA_NEW_USER_EMAIL_SUBJECT',
			$user['name'],
			$this->app->get('sitename')
		);

		// Compute the mail body.
		$emailBody = Text::sprintf(
			'PLG_USER_JOOMLA_NEW_USER_EMAIL_BODY',
			$user['name'],
			$this->app->get('sitename'),
			Uri::root(),
			$user['username'],
			$user['password_clear']
		);

		$res = Factory::getMailer()->sendMail(
			$this->app->get('mailfrom'),
			$this->app->get('fromname'),
			$user['email'],
			$emailSubject,
			$emailBody
		);

		if ($res === false)
		{
			$this->app->enqueueMessage(Text::_('JERROR_SENDING_EMAIL'),
'warning');
		}

		// Set application language back to default if we changed it
		if ($userLocale !== $defaultLocale)
		{
			$lang->setLanguage($defaultLocale);
		}
	}

	/**
	 * This method should handle any login logic and report back to the
subject
	 *
	 * @param   array  $user     Holds the user data
	 * @param   array  $options  Array holding options (remember,
autoregister, group)
	 *
	 * @return  boolean  True on success
	 *
	 * @since   1.5
	 */
	public function onUserLogin($user, $options = array())
	{
		$instance = $this->_getUser($user, $options);

		// If _getUser returned an error, then pass it back.
		if ($instance instanceof Exception)
		{
			return false;
		}

		// If the user is blocked, redirect with an error
		if ($instance->block == 1)
		{
			$this->app->enqueueMessage(Text::_('JERROR_NOLOGIN_BLOCKED'),
'warning');

			return false;
		}

		// Authorise the user based on the group information
		if (!isset($options['group']))
		{
			$options['group'] = 'USERS';
		}

		// Check the user can login.
		$result = $instance->authorise($options['action']);

		if (!$result)
		{
			$this->app->enqueueMessage(Text::_('JERROR_LOGIN_DENIED'),
'warning');

			return false;
		}

		// Mark the user as logged in
		$instance->guest = 0;

		$session = Factory::getSession();

		// Grab the current session ID
		$oldSessionId = $session->getId();

		// Fork the session
		$session->fork();

		$session->set('user', $instance);

		// Ensure the new session's metadata is written to the database
		$this->app->checkSession();

		// Purge the old session
		$query = $this->db->getQuery(true)
			->delete('#__session')
			->where($this->db->quoteName('session_id') . ' =
' . $this->db->quoteBinary($oldSessionId));

		try
		{
			$this->db->setQuery($query)->execute();
		}
		catch (RuntimeException $e)
		{
			// The old session is already invalidated, don't let this block
logging in
		}

		// Hit the user last visit field
		$instance->setLastVisit();

		// Add "user state" cookie used for reverse caching proxies
like Varnish, Nginx etc.
		if ($this->app->isClient('site'))
		{
			$this->app->input->cookie->set(
				'joomla_user_state',
				'logged_in',
				0,
				$this->app->get('cookie_path', '/'),
				$this->app->get('cookie_domain', ''),
				$this->app->isHttpsForced(),
				true
			);
		}

		return true;
	}

	/**
	 * This method should handle any logout logic and report back to the
subject
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (client, ...).
	 *
	 * @return  boolean  True on success
	 *
	 * @since   1.5
	 */
	public function onUserLogout($user, $options = array())
	{
		$my      = Factory::getUser();
		$session = Factory::getSession();

		// Make sure we're a valid user first
		if ($user['id'] == 0 &&
!$my->get('tmp_user'))
		{
			return true;
		}

		$sharedSessions = $this->app->get('shared_session',
'0');

		// Check to see if we're deleting the current session
		if ($my->id == $user['id'] && ($sharedSessions ||
(!$sharedSessions && $options['clientid'] ==
$this->app->getClientId())))
		{
			// Hit the user last visit field
			$my->setLastVisit();

			// Destroy the php session for this user
			$session->destroy();
		}

		// Enable / Disable Forcing logout all users with same userid
		$forceLogout = $this->params->get('forceLogout', 1);

		if ($forceLogout)
		{
			$clientId = (!$sharedSessions) ? (int) $options['clientid'] :
null;

			UserHelper::destroyUserSessions($user['id'], false,
$clientId);
		}

		// Delete "user state" cookie used for reverse caching proxies
like Varnish, Nginx etc.
		if ($this->app->isClient('site'))
		{
			$this->app->input->cookie->set('joomla_user_state',
'', 1, $this->app->get('cookie_path',
'/'), $this->app->get('cookie_domain',
''));
		}

		return true;
	}

	/**
	 * This method will return a user object
	 *
	 * If options['autoregister'] is true, if the user doesn't
exist yet they will be created
	 *
	 * @param   array  $user     Holds the user data.
	 * @param   array  $options  Array holding options (remember,
autoregister, group).
	 *
	 * @return  User
	 *
	 * @since   1.5
	 */
	protected function _getUser($user, $options = array())
	{
		$instance = User::getInstance();
		$id = (int) UserHelper::getUserId($user['username']);

		if ($id)
		{
			$instance->load($id);

			return $instance;
		}

		// TODO : move this out of the plugin
		$params = ComponentHelper::getParams('com_users');

		// Read the default user group option from com_users
		$defaultUserGroup = $params->get('new_usertype',
$params->get('guest_usergroup', 1));

		$instance->id = 0;
		$instance->name = $user['fullname'];
		$instance->username = $user['username'];
		$instance->password_clear = $user['password_clear'];

		// Result should contain an email (check).
		$instance->email = $user['email'];
		$instance->groups = array($defaultUserGroup);

		// If autoregister is set let's register the user
		$autoregister = isset($options['autoregister']) ?
$options['autoregister'] :
$this->params->get('autoregister', 1);

		if ($autoregister)
		{
			if (!$instance->save())
			{
				JLog::add('Error in autoregistration for user ' .
$user['username'] . '.', JLog::WARNING,
'error');
			}
		}
		else
		{
			// No existing user and autoregister off, this is a temporary user.
			$instance->set('tmp_user', true);
		}

		return $instance;
	}
}
user/joomla/joomla.xml000064400000003417147357022250011022 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="user" method="upgrade">
	<name>plg_user_joomla</name>
	<author>Joomla! Project</author>
	<creationDate>December 2006</creationDate>
	<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_USER_JOOMLA_XML_DESCRIPTION</description>
	<files>
		<filename plugin="joomla">joomla.php</filename>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_user_joomla.ini</language>
		<language
tag="en-GB">en-GB.plg_user_joomla.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<field
					name="autoregister"
					type="radio"
					label="PLG_USER_JOOMLA_FIELD_AUTOREGISTER_LABEL"
					description="PLG_USER_JOOMLA_FIELD_AUTOREGISTER_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="mail_to_user"
					type="radio"
					label="PLG_USER_JOOMLA_FIELD_MAILTOUSER_LABEL"
					description="PLG_USER_JOOMLA_FIELD_MAILTOUSER_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>

				<field
					name="forceLogout"
					type="radio"
					label="PLG_USER_JOOMLA_FIELD_FORCELOGOUT_LABEL"
					description="PLG_USER_JOOMLA_FIELD_FORCELOGOUT_DESC"
					class="btn-group btn-group-yesno"
					default="1"
					>
					<option value="1">JYES</option>
					<option value="0">JNO</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
user/profile/field/dob.php000064400000002720147357022250011532
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.profile
 *
 * @copyright   (C) 2014 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

JFormHelper::loadFieldClass('calendar');

/**
 * Provides input for "Date of Birth" field
 *
 * @package     Joomla.Plugin
 * @subpackage  User.profile
 * @since       3.3.7
 */
class JFormFieldDob extends JFormFieldCalendar
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.3.7
	 */
	protected $type = 'Dob';

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   3.3.7
	 */
	protected function getLabel()
	{
		$label = parent::getLabel();

		// Get the info text from the XML element, defaulting to empty.
		$text  = $this->element['info'] ? (string)
$this->element['info'] : '';
		$text  = $this->translateLabel ? JText::_($text) : $text;

		if ($text)
		{
			$app    = JFactory::getApplication();
			$layout = new JLayoutFile('plugins.user.profile.fields.dob');
			$view   = $app->input->getString('view', '');

			// Only display the tip when editing profile
			if ($view === 'registration' || $view === 'profile'
|| $app->isClient('administrator'))
			{
				$layout = new JLayoutFile('plugins.user.profile.fields.dob');
				$info   = $layout->render(array('text' => $text));
				$label  = $info . $label;
			}
		}

		return $label;
	}
}
user/profile/field/tos.php000064400000007025147357022250011576
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.profile
 *
 * @copyright   (C) 2012 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

JFormHelper::loadFieldClass('radio');

/**
 * Provides input for TOS
 *
 * @since  2.5.5
 */
class JFormFieldTos extends JFormFieldRadio
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  2.5.5
	 */
	protected $type = 'Tos';

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   2.5.5
	 */
	protected function getLabel()
	{
		$label = '';

		if ($this->hidden)
		{
			return $label;
		}

		// Get the label text from the XML element, defaulting to the element
name.
		$text = $this->element['label'] ? (string)
$this->element['label'] : (string)
$this->element['name'];
		$text = $this->translateLabel ? JText::_($text) : $text;

		// Set required to true as this field is not displayed at all if not
required.
		$this->required = true;

		// Build the class for the label.
		$class = !empty($this->description) ? 'hasPopover' :
'';
		$class = $class . ' required';
		$class = !empty($this->labelClass) ? $class . ' ' .
$this->labelClass : $class;

		// Add the opening label tag and main attributes attributes.
		$label .= '<label id="' . $this->id .
'-lbl" for="' . $this->id . '"
class="' . $class . '"';

		// If a description is specified, use it to build a tooltip.
		if (!empty($this->description))
		{
			$label .= ' title="' . htmlspecialchars(trim($text,
':'), ENT_COMPAT, 'UTF-8') . '"';
			$label .= ' data-content="' . htmlspecialchars(
				$this->translateDescription ? JText::_($this->description) :
$this->description,
				ENT_COMPAT,
				'UTF-8'
			) . '"';

			if (JFactory::getLanguage()->isRtl())
			{
				$label .= ' data-placement="left"';
			}
		}

		$tosArticle = $this->element['article'] > 0 ? (int)
$this->element['article'] : 0;

		if ($tosArticle)
		{
			JHtml::_('behavior.modal');
			JLoader::register('ContentHelperRoute', JPATH_BASE .
'/components/com_content/helpers/route.php');

			$attribs          = array();
			$attribs['class'] = 'modal';
			$attribs['rel']   = '{handler: \'iframe\',
size: {x:800, y:500}}';

			$db    = JFactory::getDbo();
			$query = $db->getQuery(true);
			$query->select('id, alias, catid, language')
				->from('#__content')
				->where('id = ' . $tosArticle);
			$db->setQuery($query);
			$article = $db->loadObject();

			if (JLanguageAssociations::isEnabled())
			{
				$tosAssociated =
JLanguageAssociations::getAssociations('com_content',
'#__content', 'com_content.item', $tosArticle);
			}

			$currentLang = JFactory::getLanguage()->getTag();

			if (isset($tosAssociated) && $currentLang !==
$article->language && array_key_exists($currentLang,
$tosAssociated))
			{
				$url = ContentHelperRoute::getArticleRoute(
					$tosAssociated[$currentLang]->id,
					$tosAssociated[$currentLang]->catid,
					$tosAssociated[$currentLang]->language
				);

				$link = JHtml::_('link', JRoute::_($url .
'&tmpl=component'), $text, $attribs);
			}
			else
			{
				$slug = $article->alias ? ($article->id . ':' .
$article->alias) : $article->id;
				$url  = ContentHelperRoute::getArticleRoute($slug, $article->catid,
$article->language);
				$link = JHtml::_('link', JRoute::_($url .
'&tmpl=component'), $text, $attribs);
			}
		}
		else
		{
			$link = $text;
		}

		// Add the label text and closing tag.
		$label .= '>' . $link . '<span
class="star">&#160;*</span></label>';

		return $label;
	}
}
user/profile/profile.php000064400000032073147357022250011347
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.profile
 *
 * @copyright   (C) 2009 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Date\Date;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormHelper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\String\PunycodeHelper;
use Joomla\Utilities\ArrayHelper;

/**
 * An example custom profile plugin.
 *
 * @since  1.6
 */
class PlgUserProfile extends JPlugin
{
	/**
	 * Date of birth.
	 *
	 * @var    string
	 * @since  3.1
	 */
	private $date = '';

	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Constructor
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An array that holds the plugin
configuration
	 *
	 * @since   1.5
	 */
	public function __construct(& $subject, $config)
	{
		parent::__construct($subject, $config);
		FormHelper::addFieldPath(__DIR__ . '/field');
	}

	/**
	 * Runs on content preparation
	 *
	 * @param   string  $context  The context for the data
	 * @param   object  $data     An object containing the data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onContentPrepareData($context, $data)
	{
		// Check we are manipulating a valid form.
		if (!in_array($context, array('com_users.profile',
'com_users.user', 'com_users.registration',
'com_admin.profile')))
		{
			return true;
		}

		if (is_object($data))
		{
			$userId = isset($data->id) ? $data->id : 0;

			if (!isset($data->profile) && $userId > 0)
			{
				// Load the profile data from the database.
				$db = Factory::getDbo();
				$db->setQuery(
					'SELECT profile_key, profile_value FROM #__user_profiles'
						. ' WHERE user_id = ' . (int) $userId . " AND
profile_key LIKE 'profile.%'"
						. ' ORDER BY ordering'
				);

				try
				{
					$results = $db->loadRowList();
				}
				catch (RuntimeException $e)
				{
					$this->_subject->setError($e->getMessage());

					return false;
				}

				// Merge the profile data.
				$data->profile = array();

				foreach ($results as $v)
				{
					$k = str_replace('profile.', '', $v[0]);
					$data->profile[$k] = json_decode($v[1], true);

					if ($data->profile[$k] === null)
					{
						$data->profile[$k] = $v[1];
					}
				}
			}

			if (!HTMLHelper::isRegistered('users.url'))
			{
				HTMLHelper::register('users.url', array(__CLASS__,
'url'));
			}

			if (!HTMLHelper::isRegistered('users.calendar'))
			{
				HTMLHelper::register('users.calendar', array(__CLASS__,
'calendar'));
			}

			if (!HTMLHelper::isRegistered('users.tos'))
			{
				HTMLHelper::register('users.tos', array(__CLASS__,
'tos'));
			}

			if (!HTMLHelper::isRegistered('users.dob'))
			{
				HTMLHelper::register('users.dob', array(__CLASS__,
'dob'));
			}
		}

		return true;
	}

	/**
	 * Returns an anchor tag generated from a given value
	 *
	 * @param   string  $value  URL to use
	 *
	 * @return  mixed|string
	 */
	public static function url($value)
	{
		if (empty($value))
		{
			return HTMLHelper::_('users.value', $value);
		}
		else
		{
			// Convert website URL to utf8 for display
			$value = PunycodeHelper::urlToUTF8(htmlspecialchars($value));

			if (strpos($value, 'http') === 0)
			{
				return '<a href="' . $value . '">'
. $value . '</a>';
			}
			else
			{
				return '<a href="http://' . $value .
'">' . $value . '</a>';
			}
		}
	}

	/**
	 * Returns html markup showing a date picker
	 *
	 * @param   string  $value  valid date string
	 *
	 * @return  mixed
	 */
	public static function calendar($value)
	{
		if (empty($value))
		{
			return HTMLHelper::_('users.value', $value);
		}
		else
		{
			return HTMLHelper::_('date', $value, null, null);
		}
	}

	/**
	 * Returns the date of birth formatted and calculated using server
timezone.
	 *
	 * @param   string  $value  valid date string
	 *
	 * @return  mixed
	 */
	public static function dob($value)
	{
		if (!$value)
		{
			return '';
		}

		return HTMLHelper::_('date', $value,
Text::_('DATE_FORMAT_LC1'), false);
	}

	/**
	 * Return the translated strings yes or no depending on the value
	 *
	 * @param   boolean  $value  input value
	 *
	 * @return  string
	 */
	public static function tos($value)
	{
		if ($value)
		{
			return Text::_('JYES');
		}
		else
		{
			return Text::_('JNO');
		}
	}

	/**
	 * Adds additional fields to the user editing form
	 *
	 * @param   Form   $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   1.6
	 */
	public function onContentPrepareForm(Form $form, $data)
	{
		// Check we are manipulating a valid form.
		$name = $form->getName();

		if (!in_array($name, array('com_admin.profile',
'com_users.user', 'com_users.profile',
'com_users.registration')))
		{
			return true;
		}

		// Add the registration fields to the form.
		Form::addFormPath(__DIR__ . '/profiles');
		$form->loadFile('profile');

		$fields = array(
			'address1',
			'address2',
			'city',
			'region',
			'country',
			'postal_code',
			'phone',
			'website',
			'favoritebook',
			'aboutme',
			'dob',
			'tos',
		);

		// Change fields description when displayed in frontend or backend
profile editing
		$app = Factory::getApplication();

		if ($app->isClient('site') || $name ===
'com_users.user' || $name === 'com_admin.profile')
		{
			$form->setFieldAttribute('address1',
'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE',
'profile');
			$form->setFieldAttribute('address2',
'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE',
'profile');
			$form->setFieldAttribute('city', 'description',
'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('region', 'description',
'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('country',
'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE',
'profile');
			$form->setFieldAttribute('postal_code',
'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE',
'profile');
			$form->setFieldAttribute('phone', 'description',
'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('website',
'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE',
'profile');
			$form->setFieldAttribute('favoritebook',
'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE',
'profile');
			$form->setFieldAttribute('aboutme',
'description', 'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE',
'profile');
			$form->setFieldAttribute('dob', 'description',
'PLG_USER_PROFILE_FILL_FIELD_DESC_SITE', 'profile');
			$form->setFieldAttribute('tos', 'description',
'PLG_USER_PROFILE_FIELD_TOS_DESC_SITE', 'profile');
		}

		$tosArticle = $this->params->get('register_tos_article');
		$tosEnabled = $this->params->get('register-require_tos',
0);

		// We need to be in the registration form and field needs to be enabled
		if ($name !== 'com_users.registration' || !$tosEnabled)
		{
			// We only want the TOS in the registration form
			$form->removeField('tos', 'profile');
		}
		else
		{
			// Push the TOS article ID into the TOS field.
			$form->setFieldAttribute('tos', 'article',
$tosArticle, 'profile');
		}

		foreach ($fields as $field)
		{
			// Case using the users manager in admin
			if ($name === 'com_users.user')
			{
				// Toggle whether the field is required.
				if ($this->params->get('profile-require_' . $field, 1)
> 0)
				{
					$form->setFieldAttribute($field, 'required',
($this->params->get('profile-require_' . $field) == 2) ?
'required' : '', 'profile');
				}
				// Remove the field if it is disabled in registration and profile
				elseif ($this->params->get('register-require_' .
$field, 1) == 0
					&& $this->params->get('profile-require_' .
$field, 1) == 0)
				{
					$form->removeField($field, 'profile');
				}
			}
			// Case registration
			elseif ($name === 'com_users.registration')
			{
				// Toggle whether the field is required.
				if ($this->params->get('register-require_' . $field, 1)
> 0)
				{
					$form->setFieldAttribute($field, 'required',
($this->params->get('register-require_' . $field) == 2) ?
'required' : '', 'profile');
				}
				else
				{
					$form->removeField($field, 'profile');
				}
			}
			// Case profile in site or admin
			elseif ($name === 'com_users.profile' || $name ===
'com_admin.profile')
			{
				// Toggle whether the field is required.
				if ($this->params->get('profile-require_' . $field, 1)
> 0)
				{
					$form->setFieldAttribute($field, 'required',
($this->params->get('profile-require_' . $field) == 2) ?
'required' : '', 'profile');
				}
				else
				{
					$form->removeField($field, 'profile');
				}
			}
		}

		// Drop the profile form entirely if there aren't any fields to
display.
		$remainingfields = $form->getGroup('profile');

		if (!count($remainingfields))
		{
			$form->removeGroup('profile');
		}

		return true;
	}

	/**
	 * Method is called before user data is stored in the database
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isnew  True if a new user is stored.
	 * @param   array    $data   Holds the new user data.
	 *
	 * @return  boolean
	 *
	 * @since   3.1
	 * @throws  InvalidArgumentException on invalid date.
	 */
	public function onUserBeforeSave($user, $isnew, $data)
	{
		// Check that the date is valid.
		if (!empty($data['profile']['dob']))
		{
			try
			{
				$date = new Date($data['profile']['dob']);
				$this->date = $date->format('Y-m-d H:i:s');
			}
			catch (Exception $e)
			{
				// Throw an exception if date is not valid.
				throw new
InvalidArgumentException(Text::_('PLG_USER_PROFILE_ERROR_INVALID_DOB'));
			}

			if (Date::getInstance('now') < $date)
			{
				// Throw an exception if dob is greater than now.
				throw new
InvalidArgumentException(Text::_('PLG_USER_PROFILE_ERROR_INVALID_DOB_FUTURE_DATE'));
			}
		}

		// Check that the tos is checked if required ie only in registration from
frontend.
		$task       =
Factory::getApplication()->input->getCmd('task');
		$option     =
Factory::getApplication()->input->getCmd('option');
		$tosArticle = $this->params->get('register_tos_article');
		$tosEnabled = ($this->params->get('register-require_tos',
0) == 2);

		// Check that the tos is checked.
		if ($task === 'register' && $tosEnabled &&
$tosArticle && $option === 'com_users' &&
!$data['profile']['tos'])
		{
			throw new
InvalidArgumentException(Text::_('PLG_USER_PROFILE_FIELD_TOS_DESC_SITE'));
		}

		return true;
	}

	/**
	 * Saves user profile data
	 *
	 * @param   array    $data    entered user data
	 * @param   boolean  $isNew   true if this is a new user
	 * @param   boolean  $result  true if saving the user worked
	 * @param   string   $error   error message
	 *
	 * @return  boolean
	 */
	public function onUserAfterSave($data, $isNew, $result, $error)
	{
		$userId = ArrayHelper::getValue($data, 'id', 0,
'int');

		if ($userId && $result &&
isset($data['profile']) &&
count($data['profile']))
		{
			try
			{
				$db = Factory::getDbo();

				// Sanitize the date
				if (!empty($data['profile']['dob']))
				{
					$data['profile']['dob'] = $this->date;
				}

				$keys = array_keys($data['profile']);

				foreach ($keys as &$key)
				{
					$key = 'profile.' . $key;
					$key = $db->quote($key);
				}

				$query = $db->getQuery(true)
					->delete($db->quoteName('#__user_profiles'))
					->where($db->quoteName('user_id') . ' = ' .
(int) $userId)
					->where($db->quoteName('profile_key') . ' IN
(' . implode(',', $keys) . ')');
				$db->setQuery($query);
				$db->execute();

				$query = $db->getQuery(true)
					->select($db->quoteName('ordering'))
					->from($db->quoteName('#__user_profiles'))
					->where($db->quoteName('user_id') . ' = ' .
(int) $userId);
				$db->setQuery($query);
				$usedOrdering = $db->loadColumn();

				$tuples = array();
				$order = 1;

				foreach ($data['profile'] as $k => $v)
				{
					while (in_array($order, $usedOrdering))
					{
						$order++;
					}

					$tuples[] = '(' . $userId . ', ' .
$db->quote('profile.' . $k) . ', ' .
$db->quote(json_encode($v)) . ', ' . ($order++) .
')';
				}

				$db->setQuery('INSERT INTO #__user_profiles VALUES ' .
implode(', ', $tuples));
				$db->execute();
			}
			catch (RuntimeException $e)
			{
				$this->_subject->setError($e->getMessage());

				return false;
			}
		}

		return true;
	}

	/**
	 * Remove all user profile information for the given user ID
	 *
	 * Method is called after user data is deleted from the database
	 *
	 * @param   array    $user     Holds the user data
	 * @param   boolean  $success  True if user was successfully stored in the
database
	 * @param   string   $msg      Message
	 *
	 * @return  boolean
	 */
	public function onUserAfterDelete($user, $success, $msg)
	{
		if (!$success)
		{
			return false;
		}

		$userId = ArrayHelper::getValue($user, 'id', 0,
'int');

		if ($userId)
		{
			try
			{
				$db = Factory::getDbo();
				$db->setQuery(
					'DELETE FROM #__user_profiles WHERE user_id = ' . $userId
						. " AND profile_key LIKE 'profile.%'"
				);

				$db->execute();
			}
			catch (Exception $e)
			{
				$this->_subject->setError($e->getMessage());

				return false;
			}
		}

		return true;
	}
}
user/profile/profile.xml000064400000023570147357022250011362
0ustar00<?xml version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="user" method="upgrade">
	<name>plg_user_profile</name>
	<author>Joomla! Project</author>
	<creationDate>January 2008</creationDate>
	<copyright>(C) 2008 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.0.0</version>
	<description>PLG_USER_PROFILE_XML_DESCRIPTION</description>
	<files>
		<filename plugin="profile">profile.php</filename>
		<folder>profiles</folder>
		<folder>field</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_user_profile.ini</language>
		<language
tag="en-GB">en-GB.plg_user_profile.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic"
addfieldpath="/administrator/components/com_content/models/fields">
				<field
					name="register-require-user"
					type="spacer"
					label="PLG_USER_PROFILE_FIELD_NAME_REGISTER_REQUIRE_USER"
					class="text"
				/>

				<field
					name="register-require_address1"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ADDRESS1_LABEL"
					description="PLG_USER_PROFILE_FIELD_ADDRESS1_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_address2"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ADDRESS2_LABEL"
					description="PLG_USER_PROFILE_FIELD_ADDRESS2_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_city"
					type="list"
					label="PLG_USER_PROFILE_FIELD_CITY_LABEL"
					description="PLG_USER_PROFILE_FIELD_CITY_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_region"
					type="list"
					label="PLG_USER_PROFILE_FIELD_REGION_LABEL"
					description="PLG_USER_PROFILE_FIELD_REGION_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_country"
					type="list"
					label="PLG_USER_PROFILE_FIELD_COUNTRY_LABEL"
					description="PLG_USER_PROFILE_FIELD_COUNTRY_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_postal_code"
					type="list"
					label="PLG_USER_PROFILE_FIELD_POSTAL_CODE_LABEL"
					description="PLG_USER_PROFILE_FIELD_POSTAL_CODE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_phone"
					type="list"
					label="PLG_USER_PROFILE_FIELD_PHONE_LABEL"
					description="PLG_USER_PROFILE_FIELD_PHONE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_website"
					type="list"
					label="PLG_USER_PROFILE_FIELD_WEB_SITE_LABEL"
					description="PLG_USER_PROFILE_FIELD_WEB_SITE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_favoritebook"
					type="list"
					label="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_LABEL"
					description="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_aboutme"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ABOUT_ME_LABEL"
					description="PLG_USER_PROFILE_FIELD_ABOUT_ME_DESC"
					default="1"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="1">JOPTION_OPTIONAL</option>
					<option	value="0">JDISABLED</option>
				</field>

				<field
					name="register-require_tos"
					type="list"
					label="PLG_USER_PROFILE_FIELD_TOS_LABEL"
					description="PLG_USER_PROFILE_FIELD_TOS_DESC"
					default="0"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="0">JDISABLED</option>
				</field>

				<field
					name="register_tos_article"
					type="modal_article"
					label="PLG_USER_PROFILE_FIELD_TOS_ARTICLE_LABEL"
					description="PLG_USER_PROFILE_FIELD_TOS_ARTICLE_DESC"
					select="true"
					new="true"
					edit="true"
					clear="true"
					filter="integer"
				/>

				<field
					name="register-require_dob"
					type="list"
					label="PLG_USER_PROFILE_FIELD_DOB_LABEL"
					description="PLG_USER_PROFILE_FIELD_DOB_DESC"
					default="1"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="1">JOPTION_OPTIONAL</option>
					<option	value="0">JDISABLED</option>
				</field>

				<field
					name="spacer1"
					type="spacer"
					hr="true"
				/>

				<field
					name="profile-require-user"
					type="spacer"
					label="PLG_USER_PROFILE_FIELD_NAME_PROFILE_REQUIRE_USER"
					class="text"
				/>

				<field
					name="profile-require_address1"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ADDRESS1_LABEL"
					description="PLG_USER_PROFILE_FIELD_ADDRESS1_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_address2"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ADDRESS2_LABEL"
					description="PLG_USER_PROFILE_FIELD_ADDRESS2_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_city"
					type="list"
					label="PLG_USER_PROFILE_FIELD_CITY_LABEL"
					description="PLG_USER_PROFILE_FIELD_CITY_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_region"
					type="list"
					label="PLG_USER_PROFILE_FIELD_REGION_LABEL"
					description="PLG_USER_PROFILE_FIELD_REGION_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_country"
					type="list"
					label="PLG_USER_PROFILE_FIELD_COUNTRY_LABEL"
					description="PLG_USER_PROFILE_FIELD_COUNTRY_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_postal_code"
					type="list"
					label="PLG_USER_PROFILE_FIELD_POSTAL_CODE_LABEL"
					description="PLG_USER_PROFILE_FIELD_POSTAL_CODE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_phone"
					type="list"
					label="PLG_USER_PROFILE_FIELD_PHONE_LABEL"
					description="PLG_USER_PROFILE_FIELD_PHONE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_website"
					type="list"
					label="PLG_USER_PROFILE_FIELD_WEB_SITE_LABEL"
					description="PLG_USER_PROFILE_FIELD_WEB_SITE_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_favoritebook"
					type="list"
					label="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_LABEL"
					description="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_DESC"
					default="1"
					filter="integer"
					>
					<option value="2">JOPTION_REQUIRED</option>
					<option value="1">JOPTION_OPTIONAL</option>
					<option value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_aboutme"
					type="list"
					label="PLG_USER_PROFILE_FIELD_ABOUT_ME_LABEL"
					description="PLG_USER_PROFILE_FIELD_ABOUT_ME_DESC"
					default="1"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="1">JOPTION_OPTIONAL</option>
					<option	value="0">JDISABLED</option>
				</field>

				<field
					name="profile-require_dob"
					type="list"
					label="PLG_USER_PROFILE_FIELD_DOB_LABEL"
					description="PLG_USER_PROFILE_FIELD_DOB_DESC"
					default="1"
					filter="integer"
					>
					<option	value="2">JOPTION_REQUIRED</option>
					<option	value="1">JOPTION_OPTIONAL</option>
					<option	value="0">JDISABLED</option>
				</field>
			</fieldset>
		</fields>
	</config>
</extension>
user/profile/profiles/profile.xml000064400000005417147357022250013205
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="profile">
		<fieldset
			name="profile"
			label="PLG_USER_PROFILE_SLIDER_LABEL"
		>
			<field
				name="address1"
				type="text"
				label="PLG_USER_PROFILE_FIELD_ADDRESS1_LABEL"
				description="PLG_USER_PROFILE_FIELD_ADDRESS1_DESC"
				id="address1"
				filter="string"
				size="30"
			/>

			<field
				name="address2"
				type="text"
				label="PLG_USER_PROFILE_FIELD_ADDRESS2_LABEL"
				description="PLG_USER_PROFILE_FIELD_ADDRESS2_DESC"
				id="address2"
				filter="string"
				size="30"
			/>

			<field
				name="city"
				type="text"
				label="PLG_USER_PROFILE_FIELD_CITY_LABEL"
				description="PLG_USER_PROFILE_FIELD_CITY_DESC"
				id="city"
				filter="string"
				size="30"
			/>

			<field
				name="region"
				type="text"
				label="PLG_USER_PROFILE_FIELD_REGION_LABEL"
				description="PLG_USER_PROFILE_FIELD_REGION_DESC"
				id="region"
				filter="string"
				size="30"
			/>

			<field
				name="country"
				type="text"
				label="PLG_USER_PROFILE_FIELD_COUNTRY_LABEL"
				description="PLG_USER_PROFILE_FIELD_COUNTRY_DESC"
				id="country"
				filter="string"
				size="30"
			/>

			<field
				name="postal_code"
				type="text"
				label="PLG_USER_PROFILE_FIELD_POSTAL_CODE_LABEL"
				description="PLG_USER_PROFILE_FIELD_POSTAL_CODE_DESC"
				id="postal_code"
				filter="string"
				size="30"
			/>

			<field
				name="phone"
				type="tel"
				label="PLG_USER_PROFILE_FIELD_PHONE_LABEL"
				description="PLG_USER_PROFILE_FIELD_PHONE_DESC"
				id="phone"
				filter="string"
				size="30"
			/>

			<field
				name="website"
				type="url"
				label="PLG_USER_PROFILE_FIELD_WEB_SITE_LABEL"
				description="PLG_USER_PROFILE_FIELD_WEB_SITE_DESC"
				id="website"
				filter="url"
				size="30"
				validate="url"
			/>

			<field
				name="favoritebook"
				type="text"
				label="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_LABEL"
				description="PLG_USER_PROFILE_FIELD_FAVORITE_BOOK_DESC"
				filter="string"
				size="30"
			/>

			<field
				name="aboutme"
				type="textarea"
				label="PLG_USER_PROFILE_FIELD_ABOUT_ME_LABEL"
				description="PLG_USER_PROFILE_FIELD_ABOUT_ME_DESC"
				cols="30"
				rows="5"
				filter="safehtml"
			/>

			<field
				name="dob"
				type="dob"
				label="PLG_USER_PROFILE_FIELD_DOB_LABEL"
				description="PLG_USER_PROFILE_FIELD_DOB_DESC"
				info="PLG_USER_PROFILE_SPACER_DOB"
				translateformat="true"
				showtime="false"
				filter="server_utc"
			/>

			<field
				name="tos"
				type="tos"
				label="PLG_USER_PROFILE_FIELD_TOS_LABEL"
				description="PLG_USER_PROFILE_FIELD_TOS_DESC"
				default="0"
				filter="integer"
				>
				<option
value="1">PLG_USER_PROFILE_OPTION_AGREE</option>
				<option
value="0">PLG_USER_PROFILE_OPTION_DO_NOT_AGREE</option>
			</field>
		</fieldset>
	</fields>
</form>
user/terms/field/terms.php000064400000006324147357022250011616
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.terms
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Form\FormHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Text;

FormHelper::loadFieldClass('radio');

/**
 * Provides input for privacyterms
 *
 * @since  3.9.0
 */
class JFormFieldterms extends JFormFieldRadio
{
	/**
	 * The form field type.
	 *
	 * @var    string
	 * @since  3.9.0
	 */
	protected $type = 'terms';

	/**
	 * Method to get the field input markup.
	 *
	 * @return  string   The field input markup.
	 *
	 * @since   3.9.0
	 */
	protected function getInput()
	{
		// Display the message before the field
		echo
$this->getRenderer('plugins.user.terms.message')->render($this->getLayoutData());

		return parent::getInput();
	}

	/**
	 * Method to get the field label markup.
	 *
	 * @return  string  The field label markup.
	 *
	 * @since   3.9.0
	 */
	protected function getLabel()
	{
		if ($this->hidden)
		{
			return '';
		}

		return
$this->getRenderer('plugins.user.terms.label')->render($this->getLayoutData());
	}

	/**
	 * Method to get the data to be passed to the layout for rendering.
	 *
	 * @return  array
	 *
	 * @since   3.9.4
	 */
	protected function getLayoutData()
	{
		$data = parent::getLayoutData();

		$article = false;
		$termsArticle = $this->element['article'] > 0 ? (int)
$this->element['article'] : 0;

		if ($termsArticle &&
Factory::getApplication()->isClient('site'))
		{
			$db    = Factory::getDbo();
			$query = $db->getQuery(true)
				->select($db->quoteName(array('id', 'alias',
'catid', 'language')))
				->from($db->quoteName('#__content'))
				->where($db->quoteName('id') . ' = ' . (int)
$termsArticle);
			$db->setQuery($query);
			$article = $db->loadObject();

			JLoader::register('ContentHelperRoute', JPATH_BASE .
'/components/com_content/helpers/route.php');

			if (Associations::isEnabled())
			{
				$termsAssociated =
Associations::getAssociations('com_content',
'#__content', 'com_content.item', $termsArticle);
			}

			$currentLang = Factory::getLanguage()->getTag();

			if (isset($termsAssociated) && $currentLang !==
$article->language && array_key_exists($currentLang,
$termsAssociated))
			{
				$article->link = ContentHelperRoute::getArticleRoute(
					$termsAssociated[$currentLang]->id,
					$termsAssociated[$currentLang]->catid,
					$termsAssociated[$currentLang]->language
				);
			}
			else
			{
				$slug = $article->alias ? ($article->id . ':' .
$article->alias) : $article->id;
				$article->link = ContentHelperRoute::getArticleRoute($slug,
$article->catid, $article->language);
			}
		}

		$extraData = array(
			'termsnote' => !empty($this->element['note'])
? $this->element['note'] :
Text::_('PLG_USER_TERMS_NOTE_FIELD_DEFAULT'),
			'options' => $this->getOptions(),
			'value'   => (string) $this->value,
			'translateLabel' => $this->translateLabel,
			'translateDescription' => $this->translateDescription,
			'translateHint' => $this->translateHint,
			'termsArticle' => $termsArticle,
			'article' => $article,
		);

		return array_merge($data, $extraData);
	}
}
user/terms/terms/terms.xml000064400000000755147357022250011700
0ustar00<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="terms">
		<fieldset
			name="terms"
			label="PLG_USER_TERMS_LABEL"
		>
			<field
				name="terms"
				type="terms"
				label="PLG_USER_TERMS_FIELD_LABEL"
				description="PLG_USER_TERMS_FIELD_DESC"
				default="0"
				filter="integer"
				required="true"
				>
				<option
value="1">PLG_USER_TERMS_OPTION_AGREE</option>
				<option
value="0">PLG_USER_TERMS_OPTION_DO_NOT_AGREE</option>
			</field>
		</fieldset>
	</fields>
</form>
user/terms/terms.php000064400000011047147357022250010531 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.terms
 *
 * @copyright   (C) 2018 Open Source Matters, Inc.
<https://www.joomla.org>
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Form\Form;
use Joomla\CMS\Form\FormHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Utilities\ArrayHelper;

/**
 * An example custom terms and conditions plugin.
 *
 * @since  3.9.0
 */
class PlgUserTerms extends CMSPlugin
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $autoloadLanguage = true;

	/**
	 * Application object.
	 *
	 * @var    JApplicationCms
	 * @since  3.9.0
	 */
	protected $app;

	/**
	 * Database object.
	 *
	 * @var    JDatabaseDriver
	 * @since  3.9.0
	 */
	protected $db;

	/**
	 * Constructor
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An array that holds the plugin
configuration
	 *
	 * @since   3.9.0
	 */
	public function __construct(&$subject, $config)
	{
		parent::__construct($subject, $config);

		FormHelper::addFieldPath(__DIR__ . '/field');
	}

	/**
	 * Adds additional fields to the user registration form
	 *
	 * @param   JForm  $form  The form to be altered.
	 * @param   mixed  $data  The associated data for the form.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onContentPrepareForm($form, $data)
	{
		if (!($form instanceof JForm))
		{
			$this->_subject->setError('JERROR_NOT_A_FORM');

			return false;
		}

		// Check we are manipulating a valid form - we only display this on user
registration form.
		$name = $form->getName();

		if (!in_array($name, array('com_users.registration')))
		{
			return true;
		}

		// Add the terms and conditions fields to the form.
		Form::addFormPath(__DIR__ . '/terms');
		$form->loadFile('terms');

		$termsarticle = $this->params->get('terms_article');
		$termsnote    = $this->params->get('terms_note');

		// Push the terms and conditions article ID into the terms field.
		$form->setFieldAttribute('terms', 'article',
$termsarticle, 'terms');
		$form->setFieldAttribute('terms', 'note',
$termsnote, 'terms');
	}

	/**
	 * Method is called before user data is stored in the database
	 *
	 * @param   array    $user   Holds the old user data.
	 * @param   boolean  $isNew  True if a new user is stored.
	 * @param   array    $data   Holds the new user data.
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 * @throws  InvalidArgumentException on missing required data.
	 */
	public function onUserBeforeSave($user, $isNew, $data)
	{
		// // Only check for front-end user registration
		if ($this->app->isClient('administrator'))
		{
			return true;
		}

		$userId = ArrayHelper::getValue($user, 'id', 0,
'int');

		// User already registered, no need to check it further
		if ($userId > 0)
		{
			return true;
		}

		// Check that the terms is checked if required ie only in registration
from frontend.
		$option = $this->app->input->getCmd('option');
		$task   = $this->app->input->get->getCmd('task');
		$form   = $this->app->input->post->get('jform',
array(), 'array');

		if ($option == 'com_users' && in_array($task,
array('registration.register')) &&
empty($form['terms']['terms']))
		{
			throw new
InvalidArgumentException(Text::_('PLG_USER_TERMS_FIELD_ERROR'));
		}

		return true;
	}

	/**
	 * Saves user profile data
	 *
	 * @param   array    $data    entered user data
	 * @param   boolean  $isNew   true if this is a new user
	 * @param   boolean  $result  true if saving the user worked
	 * @param   string   $error   error message
	 *
	 * @return  boolean
	 *
	 * @since   3.9.0
	 */
	public function onUserAfterSave($data, $isNew, $result, $error)
	{
		if (!$isNew || !$result)
		{
			return true;
		}

		JLoader::register('ActionlogsModelActionlog',
JPATH_ADMINISTRATOR .
'/components/com_actionlogs/models/actionlog.php');
		$userId = ArrayHelper::getValue($data, 'id', 0,
'int');

		$message = array(
			'action'      => 'consent',
			'id'          => $userId,
			'title'       => $data['name'],
			'itemlink'    =>
'index.php?option=com_users&task=user.edit&id=' .
$userId,
			'userid'      => $userId,
			'username'    => $data['username'],
			'accountlink' =>
'index.php?option=com_users&task=user.edit&id=' .
$userId,
		);

		/* @var ActionlogsModelActionlog $model */
		$model = BaseDatabaseModel::getInstance('Actionlog',
'ActionlogsModel');
		$model->addLog(array($message),
'PLG_USER_TERMS_LOGGING_CONSENT_TO_TERMS',
'plg_user_terms', $userId);
	}
}
user/terms/terms.xml000064400000002747147357022250010551 0ustar00<?xml
version="1.0" encoding="utf-8"?>
<extension version="3.1" type="plugin"
group="user" method="upgrade">
	<name>plg_user_terms</name>
	<author>Joomla! Project</author>
	<creationDate>June 2018</creationDate>
	<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
	<license>GNU General Public License version 2 or later; see
LICENSE.txt</license>
	<authorEmail>admin@joomla.org</authorEmail>
	<authorUrl>www.joomla.org</authorUrl>
	<version>3.9.0</version>
	<description>PLG_USER_TERMS_XML_DESCRIPTION</description>
	<files>
		<filename plugin="terms">terms.php</filename>
		<folder>terms</folder>
		<folder>field</folder>
	</files>
	<languages>
		<language
tag="en-GB">en-GB.plg_user_terms.ini</language>
		<language
tag="en-GB">en-GB.plg_user_terms.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic"
addfieldpath="/administrator/components/com_content/models/fields">
				<field 
					name="terms_note" 
					type="textarea" 
					label="PLG_USER_TERMS_NOTE_FIELD_LABEL"
					description="PLG_USER_TERMS_NOTE_FIELD_DESC"
					hint="PLG_USER_TERMS_NOTE_FIELD_DEFAULT"
					class="span12"
					rows="7" 
					cols="20" 
					filter="html"
				/>	
				<field
					name="terms_article"
					type="modal_article"
					label="PLG_USER_TERMS_FIELD_ARTICLE_LABEL"
					description="PLG_USER_TERMS_FIELD_ARTICLE_DESC"
					select="true"
					new="true"
					edit="true"
					clear="true"
					filter="integer"
				/>
			</fieldset>
		</fields>
	</config>
</extension>
editors/tinymce/field/tinymcebuilder/setoptions.php000064400000001151147366113750016722
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  Editors.tinymce
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   JForm        $form    Form with extra options for the set
 * @var   JLayoutFile  $this    Context
 */

?>
<div class="setoptions-form-wrapper">
<?php foreach ($form->getGroup(null) as $field) : ?>
	<?php echo $field->renderField(); ?>
<?php endforeach; ?>
</div>
system/privacyconsent/label.php000064400000007776147366113750012765
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.privacyconsent
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   string   $autocomplete           Autocomplete attribute for the
field.
 * @var   boolean  $autofocus              Is autofocus enabled?
 * @var   string   $class                  Classes for the input.
 * @var   string   $description            Description of the field.
 * @var   boolean  $disabled               Is this field disabled?
 * @var   string   $group                  Group the field belongs to.
<fields> section in form XML.
 * @var   boolean  $hidden                 Is this field hidden in the
form?
 * @var   string   $hint                   Placeholder for the field.
 * @var   string   $id                     DOM id of the field.
 * @var   string   $label                  Label of the field.
 * @var   string   $labelclass             Classes to apply to the label.
 * @var   boolean  $multiple               Does this field support multiple
values?
 * @var   string   $name                   Name of the input field.
 * @var   string   $onchange               Onchange attribute for the
field.
 * @var   string   $onclick                Onclick attribute for the field.
 * @var   string   $pattern                Pattern (Reg Ex) of value of the
form field.
 * @var   boolean  $readonly               Is this field read only?
 * @var   boolean  $repeat                 Allows extensions to duplicate
elements.
 * @var   boolean  $required               Is this field required?
 * @var   integer  $size                   Size attribute of the input.
 * @var   boolean  $spellcheck             Spellcheck state for the form
field.
 * @var   string   $validate               Validation rules to apply.
 * @var   string   $value                  Value attribute of the field.
 * @var   array    $options                Options available for this
field.
 * @var   array    $privacynote            The privacy note that needs to
be displayed
 * @var   array    $translateLabel         Should the label be translated?
 * @var   array    $translateDescription   Should the description be
translated?
 * @var   array    $translateHint          Should the hint be translated?
 * @var   array    $privacyArticle         The Article ID holding the
Privacy Article
 * $var   object   $article                The Article object
 */

// Get the label text from the XML element, defaulting to the element name.
$text = $label ? (string) $label : (string) $name;
$text = $translateLabel ? Text::_($text) : $text;

// Set required to true as this field is not displayed at all if not
required.
$required = true;

JHtml::_('behavior.modal');

// Build the class for the label.
$class = !empty($description) ? 'hasPopover' : '';
$class = $class . ' required';
$class = !empty($labelclass) ? $class . ' ' . $labelclass :
$class;

// Add the opening label tag and main attributes.
$label = '<label id="' . $id . '-lbl"
for="' . $id . '" class="' . $class .
'"';

// If a description is specified, use it to build a tooltip.
if (!empty($description))
{
	$label .= ' title="' . htmlspecialchars(trim($text,
':'), ENT_COMPAT, 'UTF-8') . '"';
	$label .= ' data-content="' . htmlspecialchars(
		$translateDescription ? Text::_($description) : $description,
		ENT_COMPAT,
		'UTF-8'
	) . '"';
}

if (Factory::getLanguage()->isRtl())
{
	$label .= ' data-placement="left"';
}

$attribs          = array();
$attribs['class'] = 'modal';
$attribs['rel']   = '{handler: \'iframe\', size:
{x:800, y:500}}';

if ($article)
{
	$link = JHtml::_('link', Route::_($article->link .
'&tmpl=component'), $text, $attribs);
}
else
{
	$link = $text;
}

// Add the label text and closing tag.
$label .= '>' . $link . '<span
class="star">&#160;*</span></label>';

echo $label;
system/privacyconsent/message.php000064400000005055147366113750013316
0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  System.privacyconsent
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   string   $autocomplete           Autocomplete attribute for the
field.
 * @var   boolean  $autofocus              Is autofocus enabled?
 * @var   string   $class                  Classes for the input.
 * @var   string   $description            Description of the field.
 * @var   boolean  $disabled               Is this field disabled?
 * @var   string   $group                  Group the field belongs to.
<fields> section in form XML.
 * @var   boolean  $hidden                 Is this field hidden in the
form?
 * @var   string   $hint                   Placeholder for the field.
 * @var   string   $id                     DOM id of the field.
 * @var   string   $label                  Label of the field.
 * @var   string   $labelclass             Classes to apply to the label.
 * @var   boolean  $multiple               Does this field support multiple
values?
 * @var   string   $name                   Name of the input field.
 * @var   string   $onchange               Onchange attribute for the
field.
 * @var   string   $onclick                Onclick attribute for the field.
 * @var   string   $pattern                Pattern (Reg Ex) of value of the
form field.
 * @var   boolean  $readonly               Is this field read only?
 * @var   boolean  $repeat                 Allows extensions to duplicate
elements.
 * @var   boolean  $required               Is this field required?
 * @var   integer  $size                   Size attribute of the input.
 * @var   boolean  $spellcheck             Spellcheck state for the form
field.
 * @var   string   $validate               Validation rules to apply.
 * @var   string   $value                  Value attribute of the field.
 * @var   array    $options                Options available for this
field.
 * @var   array    $privacynote            The privacy note that needs to
be displayed
 * @var   array    $translateLabel         Should the label be translated?
 * @var   array    $translateDescription   Should the description be
translated?
 * @var   array    $translateHint          Should the hint be translated?
 * @var   array    $privacyArticle         The Article ID holding the
Privacy Article
 */

echo '<div class="alert alert-info">' .
$privacynote . '</div>';

user/profile/fields/dob.php000064400000001200147366113750011713
0ustar00<?php
/**
 * @package     Joomla.Site
 * @subpackage  Layout
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

/**
 * $text  string  infotext to be displayed
 */
extract($displayData);

// Closing the opening .control-group and .control-label div so we can add
our info text on own line ?>
</div></div>
<div class="controls"><?php echo $text;
?></div>
<?php // Creating new .control-group and .control-label for the actual
field ?>
<div class="control-group"><div
class="control-label">
user/terms/label.php000064400000010024147366113750010456 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.terms
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   string   $autocomplete           Autocomplete attribute for the
field.
 * @var   boolean  $autofocus              Is autofocus enabled?
 * @var   string   $class                  Classes for the input.
 * @var   string   $description            Description of the field.
 * @var   boolean  $disabled               Is this field disabled?
 * @var   string   $group                  Group the field belongs to.
<fields> section in form XML.
 * @var   boolean  $hidden                 Is this field hidden in the
form?
 * @var   string   $hint                   Placeholder for the field.
 * @var   string   $id                     DOM id of the field.
 * @var   string   $label                  Label of the field.
 * @var   string   $labelclass             Classes to apply to the label.
 * @var   boolean  $multiple               Does this field support multiple
values?
 * @var   string   $name                   Name of the input field.
 * @var   string   $onchange               Onchange attribute for the
field.
 * @var   string   $onclick                Onclick attribute for the field.
 * @var   string   $pattern                Pattern (Reg Ex) of value of the
form field.
 * @var   boolean  $readonly               Is this field read only?
 * @var   boolean  $repeat                 Allows extensions to duplicate
elements.
 * @var   boolean  $required               Is this field required?
 * @var   integer  $size                   Size attribute of the input.
 * @var   boolean  $spellcheck             Spellcheck state for the form
field.
 * @var   string   $validate               Validation rules to apply.
 * @var   string   $value                  Value attribute of the field.
 * @var   array    $options                Options available for this
field.
 * @var   array    $termsnote              The terms note that needs to be
displayed
 * @var   array    $translateLabel         Should the label be translated?
 * @var   array    $translateDescription   Should the description be
translated?
 * @var   array    $translateHint          Should the hint be translated?
 * @var   array    $termsArticle           The Article ID holding the Terms
Article
 * $var   object   $article                The Article object
 */

// Get the label text from the XML element, defaulting to the element name.
$text = $label ? (string) $label : (string) $name;
$text = $translateLabel ? Text::_($text) : $text;

// Set required to true as this field is not displayed at all if not
required.
$required = true;

JHtml::_('behavior.modal');

// Build the class for the label.
$class = !empty($description) ? 'hasPopover' : '';
$class = $class . ' required';
$class = !empty($labelclass) ? $class . ' ' . $labelclass :
$class;

// Add the opening label tag and main attributes.
$label = '<label id="' . $id . '-lbl"
for="' . $id . '" class="' . $class .
'"';

// If a description is specified, use it to build a tooltip.
if (!empty($description))
{
	$label .= ' title="' . htmlspecialchars(trim($text,
':'), ENT_COMPAT, 'UTF-8') . '"';
	$label .= ' data-content="' . htmlspecialchars(
		$translateDescription ? Text::_($description) : $description,
		ENT_COMPAT,
		'UTF-8'
	) . '"';
}

if (Factory::getLanguage()->isRtl())
{
	$label .= ' data-placement="left"';
}

$attribs          = array();
$attribs['class'] = 'modal';
$attribs['rel']   = '{handler: \'iframe\', size:
{x:800, y:500}}';

if ($article)
{
	$link = HTMLHelper::_('link', Route::_($article->link .
'&tmpl=component'), $text, $attribs);
}
else
{
	$link = $text;
}

// Add the label text and closing tag.
$label .= '>' . $link . '<span
class="star">&#160;*</span></label>';

echo $label;
user/terms/message.php000064400000005033147366113750011027 0ustar00<?php
/**
 * @package     Joomla.Plugin
 * @subpackage  User.terms
 *
 * @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license     GNU General Public License version 2 or later; see
LICENSE.txt
 */

defined('_JEXEC') or die;

extract($displayData);

/**
 * Layout variables
 * -----------------
 * @var   string   $autocomplete           Autocomplete attribute for the
field.
 * @var   boolean  $autofocus              Is autofocus enabled?
 * @var   string   $class                  Classes for the input.
 * @var   string   $description            Description of the field.
 * @var   boolean  $disabled               Is this field disabled?
 * @var   string   $group                  Group the field belongs to.
<fields> section in form XML.
 * @var   boolean  $hidden                 Is this field hidden in the
form?
 * @var   string   $hint                   Placeholder for the field.
 * @var   string   $id                     DOM id of the field.
 * @var   string   $label                  Label of the field.
 * @var   string   $labelclass             Classes to apply to the label.
 * @var   boolean  $multiple               Does this field support multiple
values?
 * @var   string   $name                   Name of the input field.
 * @var   string   $onchange               Onchange attribute for the
field.
 * @var   string   $onclick                Onclick attribute for the field.
 * @var   string   $pattern                Pattern (Reg Ex) of value of the
form field.
 * @var   boolean  $readonly               Is this field read only?
 * @var   boolean  $repeat                 Allows extensions to duplicate
elements.
 * @var   boolean  $required               Is this field required?
 * @var   integer  $size                   Size attribute of the input.
 * @var   boolean  $spellcheck             Spellcheck state for the form
field.
 * @var   string   $validate               Validation rules to apply.
 * @var   string   $value                  Value attribute of the field.
 * @var   array    $options                Options available for this
field.
 * @var   array    $termsnote              The terms note that needs to be
displayed
 * @var   array    $translateLabel         Should the label be translated?
 * @var   array    $translateDescription   Should the description be
translated?
 * @var   array    $translateHint          Should the hint be translated?
 * @var   array    $termsArticle           The Article ID holding the Terms
Article
 */

echo '<div class="alert alert-info">' .
$termsnote . '</div>';