";
+ }
+
+ $update_link = '';
+ $delete_link = '';
+
+ $a_class = 'modal-button';
+ if ( $app->isAdmin() ) {
+ $a_class = 'modal';
+ }
+
+ // Add the link to edit the attachment, if requested
+ if ( $this->some_attachments_modifiable && $attachment->user_may_edit && $this->allow_edit ) {
+
+ // Create the edit link
+ $update_url = str_replace('%d', (string)$attachment->id, $this->update_url);
+ $tooltip = JText::_('ATTACH_UPDATE_THIS_FILE') . ' (' . $actual_filename . ')';
+ $update_link = "";
+ $update_link .= JHtml::image('com_attachments/pencil.gif', $tooltip, null, true);
+ $update_link .= "";
+ }
+
+ // Add the link to delete the attachment, if requested
+ if ( $this->some_attachments_modifiable && $attachment->user_may_delete && $this->allow_edit ) {
+
+ // Create the delete link
+ $delete_url = str_replace('%d', (string)$attachment->id, $this->delete_url);
+ $tooltip = JText::_('ATTACH_DELETE_THIS_FILE') . ' (' . $actual_filename . ')';
+ $delete_link = "";
+ $delete_link .= JHtml::image('com_attachments/delete.gif', $tooltip, null, true);
+ $delete_link .= "";
+ }
+
+ if ( $this->some_attachments_modifiable && $this->allow_edit ) {
+ $html .= "
$update_link $delete_link
";
+ }
+
+ $html .= "
\n";
+ }
+
+// Close the HTML
+$html .= "
\n";
+
+if ( $format != 'raw' ) {
+ $html .= "
\n";
+ }
+
+echo $html;
diff --git a/components/com_attachments/views/attachments/tmpl/default.xml b/components/com_attachments/views/attachments/tmpl/default.xml
new file mode 100644
index 00000000..9c45fdbc
--- /dev/null
+++ b/components/com_attachments/views/attachments/tmpl/default.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/components/com_attachments/views/attachments/tmpl/index.html b/components/com_attachments/views/attachments/tmpl/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/components/com_attachments/views/attachments/tmpl/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/components/com_attachments/views/attachments/view.html.php b/components/com_attachments/views/attachments/view.html.php
new file mode 100644
index 00000000..c0f86a60
--- /dev/null
+++ b/components/com_attachments/views/attachments/view.html.php
@@ -0,0 +1,230 @@
+setMimeEncoding('text/plain');
+ }
+
+ // Add javascript
+ $uri = JFactory::getURI();
+ AttachmentsJavascript::setupJavascript();
+
+ // Get the model
+ $model = $this->getModel('Attachments');
+ if ( !$model ) {
+ $errmsg = JText::_('ATTACH_ERROR_UNABLE_TO_FIND_MODEL') . ' (ERR 63)';
+ JError::raiseError( 500, $errmsg);
+ }
+
+ // See if there are any attachments
+ $list = $model->getAttachmentsList();
+ if ( ! $list ) {
+ return null;
+ }
+
+ // if we have attachments, add the stylesheets for the attachments list
+ JHtml::stylesheet('com_attachments/attachments_list.css', array(), true);
+ $lang = JFactory::getLanguage();
+ if ( $lang->isRTL() ) {
+ JHtml::stylesheet('com_attachments/attachments_list_rtl.css', array(), true);
+ }
+
+ // Add the default path
+ $this->addTemplatePath(JPATH_SITE.'/components/com_attachments/views/attachments/tmpl');
+
+ // Set up the correct path for template overloads
+ // (Do this after previous addTemplatePath so that template overrides actually override)
+ $app = JFactory::getApplication();
+ $templateDir = JPATH_SITE.'/templates/'.$app->getTemplate().'/html/com_attachments/attachments';
+ $this->addTemplatePath($templateDir);
+
+ // Load the language files from the attachments plugin
+ $lang = JFactory::getLanguage();
+ $lang->load('plg_content_attachments', JPATH_SITE.'/plugins/content/attachments');
+
+ // Get the component parameters
+ $params = JComponentHelper::getParams('com_attachments');
+
+ // See whether the user-defined fields should be shown
+ $from = JRequest::getWord('from', 'closeme');
+ $layout = JRequest::getWord('layout');
+ $tmpl = JRequest::getWord('tmpl');
+ $task = JRequest::getWord('task');
+ $show_hidden_user_fields = false;
+ if ( $app->isAdmin() || ($from == 'editor') || ($layout == 'edit') || ($tmpl == 'component') ) {
+ $show_hidden_user_fields = true;
+ }
+ if ( $task == 'attachmentsList' ) {
+ // Always hide the hidden user fields on Ajax requests
+ $show_hidden_user_fields = false;
+ }
+
+ // User field 1
+ $show_user_field_1 = false;
+ $user_field_1_name = $params->get('user_field_1_name');
+ if ( $user_field_1_name ) {
+ if ( $show_hidden_user_fields || ($user_field_1_name[JString::strlen($user_field_1_name)-1] != '*') ) {
+ $show_user_field_1 = true;
+ $this->user_field_1_name = $user_field_1_name;
+ }
+ }
+ $this->show_user_field_1 = $show_user_field_1;
+
+ // User field 2
+ $show_user_field_2 = false;
+ $user_field_2_name = $params->get('user_field_2_name');
+ if ( $user_field_2_name ) {
+ if ( $show_hidden_user_fields || ($user_field_2_name[JString::strlen($user_field_2_name)-1] != '*') ) {
+ $show_user_field_2 = true;
+ $this->user_field_2_name = $user_field_2_name;
+ }
+ }
+ $this->show_user_field_2 = $show_user_field_2;
+
+ // User field 3
+ $show_user_field_3 = false;
+ $user_field_3_name = $params->get('user_field_3_name');
+ if ( $user_field_3_name ) {
+ if ( $show_hidden_user_fields || ($user_field_3_name[JString::strlen($user_field_3_name)-1] != '*') ) {
+ $show_user_field_3 = true;
+ $this->user_field_3_name = $user_field_3_name;
+ }
+ }
+ $this->show_user_field_3 = $show_user_field_3;
+
+ // Set up for the template
+ $parent_id = $model->getParentId();
+ $parent_type = $model->getParentType();
+ $parent_entity = JString::strtolower($model->getParentEntity());
+ // ?? fix this!
+ if ( ($parent_type == 'com_content') && ($parent_entity == 'default') ) {
+ $parent_entity = 'article';
+ }
+ $this->parent_id = $parent_id;
+ $this->parent_type = $parent_type;
+ $this->parent_entity = $parent_entity;
+ $this->parent_title = $model->getParentTitle();
+ $this->parent_entity_name = $model->getParentEntityName();
+
+ $this->some_attachments_visible = $model->someVisible();
+ $this->some_attachments_modifiable = $model->someModifiable();
+
+ $this->from = $from;
+
+ $this->list = $list;
+
+ $this->secure = $params->get('secure', false);
+
+ $this->params = $params;
+
+ // Get the display options
+ $this->superimpose_link_icons = $params->get('superimpose_url_link_icons', true);
+ $this->style = $params->get('attachments_table_style', 'attachmentsList');
+ $this->show_column_titles = $params->get('show_column_titles', false);
+ $this->show_description = $params->get('show_description', true);
+ $this->show_creator_name = $params->get('show_creator_name', false);
+ $this->show_file_size = $params->get('show_file_size', true);
+ $this->show_downloads = $params->get('show_downloads', false);
+ $this->show_created_date = $params->get('show_created_date', false);
+ $this->show_modified_date = $params->get('show_modified_date', false);
+ $this->file_link_open_mode = $params->get('file_link_open_mode', 'in_same_window');
+
+ // Set up the file/url titleshow_mod_date
+ if ( $this->show_column_titles ) {
+ switch ( $model->types() ) {
+ case 'file':
+ $this->file_url_title = JText::_('ATTACH_FILE');
+ break;
+ case 'url':
+ $this->file_url_title = JText::_('ATTACH_URL');
+ break;
+ default:
+ $this->file_url_title = JText::_('ATTACH_FILE_URL');
+ }
+ }
+
+ if ( $this->show_created_date OR $this->show_modified_date ) {
+ $this->date_format = $params->get('date_format', '%Y-%m-%d %I:%M%P');
+ }
+
+ // Get the attachments list title
+ $title = $this->title;
+ if ( !$title || (JString::strlen($title) == 0) ) {
+ $title = 'ATTACH_ATTACHMENTS_TITLE';
+ }
+ $parent = $model->getParentClass();
+ $title = $parent->attachmentsListTitle($title, $parent_id, $parent_entity);
+ $this->title = $title; // Note: assume it is translated
+
+ // Construct the path for the icons
+ $uri = JFactory::getURI();
+ $base_url = $uri->root(false);
+ $this->base_url = $base_url;
+ $this->icon_url_base = $base_url . 'components/com_attachments/media/icons/';
+
+ // Get the output of the template
+ $result = $this->loadTemplate($tpl);
+ if (JError::isError($result)) {
+ return $result;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the output
+ *
+ * @return string the output
+ */
+ public function getOutput()
+ {
+ return $this->_output;
+ }
+
+}
diff --git a/components/com_attachments/views/attachments/view.raw.php b/components/com_attachments/views/attachments/view.raw.php
new file mode 100644
index 00000000..c336cdc9
--- /dev/null
+++ b/components/com_attachments/views/attachments/view.raw.php
@@ -0,0 +1,18 @@
+
+ * @copyright Copyright (C) 2009-2018 Jonathan M. Cameron, All Rights Reserved
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ * @link http://joomlacode.org/gf/project/attachments/frs/
+ */
+
+// No direct access
+defined('_JEXEC') or die('Restricted access');
+
+/** Load the attachments plugin class */
+if (!JPluginHelper::importPlugin('attachments', 'attachments_plugin_framework'))
+{
+ // Fail gracefully if the Attachments plugin framework plugin is disabled
+ return;
+}
+
+
+/**
+ * The class for the Attachments plugin for regular Joomla! content (articles, categories)
+ *
+ * @package Attachments
+ * @since 3.0
+ */
+class AttachmentsPlugin_Com_Content extends AttachmentsPlugin
+{
+ /**
+ * Constructor
+ *
+ * @param object &$subject The object to observe
+ * @param array $config An optional associative array of configuration settings.
+ *
+ * Recognized key values include 'name', 'group', 'params', 'language'
+ * (this list is not meant to be comprehensive).
+ */
+ public function __construct(&$subject, $config = array())
+ {
+ parent::__construct($subject, $config);
+
+ // Configure the plugin
+ $this->_name = 'attachments_for_content';
+
+ // Set basic attachments defaults
+ $this->parent_type = 'com_content';
+ $this->default_entity = 'article';
+
+ // Add the information about the default entity (article)
+ $this->entities[] = 'article';
+ $this->entity_name['article'] = 'article';
+ $this->entity_name['default'] = 'article';
+ $this->entity_table['article'] = 'content';
+ $this->entity_id_field['article'] = 'id';
+ $this->entity_title_field['article'] = 'title';
+
+ // Add information about the category description entity
+ $this->entities[] = 'category';
+ $this->entity_name['category'] = 'category';
+ $this->entity_table['category'] = 'categories';
+ $this->entity_id_field['category'] = 'id';
+ $this->entity_title_field['category'] = 'title';
+
+ // Always load the language
+ $this->loadLanguage();
+ }
+
+ /**
+ * Determine the parent entity
+ *
+ * From the view and the class of the parent (row of onPrepareContent plugin),
+ * determine what the entity type is for this entity.
+ *
+ * @param &object &$parent The object for the parent (row) that onPrepareContent gets
+ *
+ * @return the correct parent entity (eg, 'article', 'category')
+ */
+ public function determineParentEntity(&$parent)
+ {
+ $view = JRequest::getCmd('view');
+
+ // Handle category calls
+ if (($view == 'category') && (get_class($parent) == 'JTableContent'))
+ {
+ return 'category';
+ }
+
+ // Handle everything else (articles)
+ // (apparently this is called before parents are displayed so ignore those calls)
+ if (isset($parent->id))
+ {
+ return 'default';
+ }
+
+ return false;
+ }
+
+ /**
+ * Return the name of the field with the content item text
+ *
+ * During the display of content items (eg, articles, categories), the
+ * onContentPrepare (etc) callbacks are used to insert attachments lists.
+ * The second argument of the onContentPrepare() function is an object
+ * (usually $row) for the content item (eg, article). This function will
+ * return the appropriate field for the text of the content item. In some
+ * cases it is 'text', in others, 'introtext'. Attachments plugins can
+ * override this function to provide the field name more intelligently.
+ *
+ * Note: returns null if the text field is unknown/not present.
+ *
+ * @param &object &$row the content object (eg, article) being displayed
+ * @param string $parent_entity the type of entity for this content item.
+ *
+ * @return string name of the text field of this content item object.
+ */
+ protected function getTextFieldName(&$row, $parent_entity)
+ {
+ $view = JRequest::getCmd('view');
+ $layout = JRequest::getCmd('layout');
+
+ $text_field_name = parent::getTextFieldName($row, $parent_entity);
+
+ // In the case of a blog, we know what text_field_name should be
+ if (isset($row->introtext) AND ($layout == 'blog'))
+ {
+ $text_field_name = 'introtext';
+ }
+
+ // Featured also uses 'introtext'
+ if (isset($row->introtext) AND ($view == 'featured'))
+ {
+ $text_field_name = 'introtext';
+ }
+
+ // Check for non-menu category view
+ if (isset($row->introtext) AND ($view == 'category') AND
+ (($parent_entity == 'default') OR ($parent_entity == 'article')))
+ {
+ $text_field_name = 'introtext';
+ }
+
+ if (version_compare(JVERSION, '3.4.0', 'ge') AND
+ ($view == 'category') AND ($layout == 'blog') AND ($parent_entity == 'article'))
+ {
+ $text_field_name = 'text';
+ }
+
+ return $text_field_name;
+ }
+
+ /**
+ * Return the URL that can be called to select a specific content item.
+ *
+ * @param string $parent_entity the type of entity to select from
+ *
+ * @return the URL that can be called to select a specific content item
+ */
+ public function getSelectEntityURL($parent_entity = 'default')
+ {
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ switch ($parent_entity)
+ {
+
+ case 'category':
+ return parent::getSelectEntityURL($parent_entity);
+ break;
+
+ default:
+ return "index.php?option=com_content&view=articles&layout=modal&tmpl=component&function=jSelectParentArticle";
+ }
+ }
+
+ /**
+ * Return an array of entity items (with id,title pairs for each item)
+ *
+ * @param string $parent_entity the type of entity to search for
+ * @param string $filter filter the results for matches for this filter string
+ *
+ * @return the array of entity id,title pairs
+ */
+ public function getEntityItems($parent_entity = 'default', $filter = '')
+ {
+ $db = JFactory::getDBO();
+
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+ $parent_entity_name = JText::_('ATTACH_' . $parent_entity);
+
+ // Note that article is handled separately
+ if (JString::strtolower($parent_entity) != 'category')
+ {
+ $errmsg = JText::sprintf('ATTACH_ERROR_GETTING_LIST_OF_ENTITY_S_ITEMS', $parent_entity_name) . ' (ERR 400)';
+ JError::raiseError(500, $errmsg);
+ }
+
+ $entity_table = $this->entity_table[$parent_entity];
+ $entity_title_field = $this->entity_title_field[$parent_entity];
+ $entity_id_field = $this->entity_id_field[$parent_entity];
+
+ // Get the ordering information
+ $app = JFactory::getApplication();
+ $order = $app->getUserStateFromRequest('com_attachments.selectEntity.filter_order', 'filter_order', '', 'cmd');
+ $order_Dir = $app->getUserStateFromRequest('com_attachments.selectEntity.filter_order_Dir', 'filter_order_Dir', '', 'word');
+
+ // Get all the items
+ $query = $db->getQuery(true);
+ $query->select('*')->from('#__categories');
+
+ // Filter
+ if ($filter)
+ {
+ $filter = $db->quote('%' . $db->escape($filter, true) . '%', false);
+ $query->where('title LIKE ' . $filter);
+ }
+ $query->where('extension=' . $db->quote('com_content'));
+
+ // NOTE: Ignore any requested order since only ordering by lft makes the hierarchy work
+ $query->order('lft');
+
+ // Do the query
+ $db->setQuery($query);
+ $items = $db->loadObjectList();
+ if ($db->getErrorNum())
+ {
+ $errmsg = JText::sprintf('ATTACH_ERROR_GETTING_LIST_OF_ENTITY_S_ITEMS', $parent_entity_name) . ' (ERR 401) ' . $db->stderr();
+ JError::raiseError(500, $errmsg);
+ }
+
+ if ($items == null)
+ {
+ return null;
+ }
+
+ // Set up the hierarchy indenting
+ foreach ($items as &$item)
+ {
+ $repeat = ($item->level - 1 >= 0) ? $item->level - 1 : 0;
+ $item->title = str_repeat('- ', $repeat) . $item->title;
+ }
+
+ return $items;
+ }
+
+ /**
+ * Return the ID of the creator/owner of the parent entity
+ *
+ * @param int $parent_id the ID for the parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return creators id if found, 0 otherwise
+ */
+ public function getParentCreatorId($parent_id, $parent_entity = 'default')
+ {
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+
+ $result = 0;
+
+ // Return the right thing for each entity
+ switch ($parent_entity)
+ {
+
+ case 'category':
+ $query->select('created_user_id')->from('#__categories')->where('id = ' . (int) $parent_id);
+ $db->setQuery($query, 0, 1);
+ $result = $db->loadResult();
+ if ($db->getErrorNum())
+ {
+ $errmsg = JText::_('ATTACH_ERROR_CHECKING_CATEGORY_PERMISSIONS') . ' (ERR 402)';
+ JError::raiseError(500, $errmsg);
+ }
+ break;
+
+ default: // Article
+ $query->select('created_by')->from('#__content')->where('id = ' . (int) $parent_id);
+ $db->setQuery($query, 0, 1);
+ $result = $db->loadResult();
+ if ($db->getErrorNum())
+ {
+ $errmsg = JText::_('ATTACH_ERROR_CHECKING_ARTICLE_PERMISSIONS') . ' (ERR 403)';
+ JError::raiseError(500, $errmsg);
+ }
+ }
+
+ if (is_numeric($result))
+ {
+ return (int) $result;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Get a URL to view the content article
+ *
+ * @param int $parent_id the ID for this parent object
+ * @param string $parent_entity the type of parent element/entity
+ *
+ * @return a URL to view the entity (non-SEF form)
+ */
+ public function getEntityViewURL($parent_id, $parent_entity = 'default')
+ {
+ $uri = JFactory::getURI();
+
+ $base_url = $uri->root(true) . '/';
+
+ // Return the right thing for each entity
+ switch ($parent_entity)
+ {
+
+ case 'category':
+ return $base_url . 'index.php?option=com_content&view=category&id=' . $parent_id;
+ break;
+
+ default:
+ return $base_url . 'index.php?option=com_content&view=article&id=' . $parent_id;
+ }
+ }
+
+ /**
+ * Get a URL to add an attachment to a specific entity
+ *
+ * @param int $parent_id the ID for the parent entity object (null if the parent does not exist)
+ * @param string $parent_entity the type of entity for this parent type
+ * @param string $from where the call should return to
+ *
+ * @return the url to add a new attachments to the specified entity
+ */
+ public function getEntityAddUrl($parent_id, $parent_entity = 'default', $from = 'closeme')
+ {
+ $app = JFactory::getApplication();
+
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ // Determine the task
+ if ($app->isAdmin())
+ {
+ $task = 'attachment.add';
+ }
+ else
+ {
+ $task = 'upload';
+ }
+
+ // Handle article creation
+ $url = "index.php?option=com_attachments&task=$task";
+ if ($parent_id == null)
+ {
+ $url .= "&parent_id=$parent_id,new";
+ }
+ else
+ {
+ $url .= "&parent_id=$parent_id";
+ }
+
+ // Build the right URL for each entity
+ switch ($parent_entity)
+ {
+
+ case 'category':
+ $url .= "&parent_type=com_content.$parent_entity&from=$from";
+ break;
+
+ default:
+ $url .= "&parent_type=com_content.article&from=$from";
+ }
+
+ return $url;
+ }
+
+ /**
+ * Check to see if a custom title applies to this parent
+ *
+ * Note: this function assumes that the parent_id's match
+ *
+ * @param string $parent_entity parent entity for the parent of the list
+ * @param string $rtitle_parent_entity the entity of the candidate attachment list title (from params)
+ *
+ * @return true if the custom title should be used
+ */
+ public function checkAttachmentsListTitle($parent_entity, $rtitle_parent_entity)
+ {
+ if ((($parent_entity == 'default') || ($parent_entity == 'article'))
+ && (($rtitle_parent_entity == 'default') || ($rtitle_parent_entity == 'article')))
+ {
+ return true;
+ }
+
+ if (($parent_entity == 'category') && ($parent_entity == $rtitle_parent_entity))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Is the parent new (based on the parent_id)
+ *
+ * @param object &$attachment the attachment
+ *
+ * @return true if the parent is new (being created)
+ */
+ public function newParent(&$attachment)
+ {
+ if ($attachment->parent_id != 0) {
+ return false;
+ }
+
+ if ($attachment->parent_entity == 'article') {
+ // Seems to be true for articles
+ return true;
+ }
+
+ if ($attachment->parent_entity == 'category') {
+ // Assume this is true for category (but not sure)
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Check to see if the parent is published
+ *
+ * @param int $parent_id is the ID for this parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return true if the parent is published
+ */
+ public function isParentPublished($parent_id, $parent_entity = 'default')
+ {
+ $db = JFactory::getDBO();
+
+ $published = false;
+
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+ $parent_entity_name = JText::_('ATTACH_' . $parent_entity);
+
+ // Return the right thing for each entity
+ switch ($parent_entity)
+ {
+
+ case 'category':
+ $entity_table = $this->entity_table[$parent_entity];
+ $query = $db->getQuery(true);
+ $query->select('published')->from("#__$entity_table")->where('id = ' . (int) $parent_id);
+ $db->setQuery($query, 0, 1);
+ $obj = $db->loadObject();
+ if ($db->getErrorNum())
+ {
+ $errmsg = JText::sprintf('ATTACH_ERROR_INVALID_PARENT_S_ID_N', $parent_entity_name, $parent_id) . ' (ERR 404)';
+ JError::raiseError(500, $errmsg);
+ }
+ if (is_object($obj))
+ {
+ $published = $obj->published == 1;
+ }
+ else
+ {
+ $published = false;
+ }
+ break;
+
+ default:
+
+ // Check for articles
+ $query = $db->getQuery(true);
+ $query->select('state, publish_up, publish_down')->from('#__content');
+ $query->where('id = ' . (int) $parent_id);
+ $db->setQuery($query, 0, 1);
+ $article = $db->loadObject();
+ if ($db->getErrorNum())
+ {
+ $errmsg = JText::sprintf('ATTACH_ERROR_INVALID_PARENT_S_ID_N', $parent_entity_name, $parent_id) . ' (ERR 405)';
+ JError::raiseError(500, $errmsg);
+ }
+ else
+ {
+ $now = JFactory::getDate()->toUnix();
+ $nullDate = JFactory::getDate($db->getNullDate())->toUnix();
+
+ if ($article)
+ {
+ $publish_up = JFactory::getDate($article->publish_up)->toUnix();
+ $publish_down = JFactory::getDate($article->publish_down)->toUnix();
+
+ $published = (($article->state == 1) && ($now >= $publish_up) && (($publish_down == $nullDate) || ($now <= $publish_down)));
+ }
+ else
+ {
+ $published = false;
+ }
+ }
+ }
+
+ return $published;
+ }
+
+ /**
+ * Check to see if the parent is archived
+ *
+ * @param int $parent_id is the ID for this parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return true if the parent is archived
+ */
+ public function isParentArchived($parent_id, $parent_entity = 'default')
+ {
+ $archived = false;
+
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ // Return the right thing for each entity
+ switch ($parent_entity)
+ {
+
+ case 'category':
+ // You apparently cannot archive categories
+ break;
+
+ default:
+ // Articles
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $query->select('state')->from('#__content')->where(' id = ' . (int) $parent_id);
+ $db->setQuery($query, 0, 1);
+ $article = $db->loadObject();
+ if ($db->getErrorNum())
+ {
+ $parent_entity_name = JText::_('ATTACH_' . $parent_entity);
+ $errmsg = JText::sprintf('ATTACH_ERROR_INVALID_PARENT_S_ID_N', $parent_entity_name, $parent_id) . ' (ERR 406)';
+ JError::raiseError(500, $errmsg);
+ }
+ else
+ {
+ if ($article)
+ {
+ $archived = $article->state == -1;
+ }
+ else
+ {
+ $archived = false;
+ }
+ }
+ }
+
+ return $archived;
+ }
+
+ /**
+ * Return a string of the where clause for filtering the the backend list of attachments
+ *
+ * @param string $parent_state the state ('ALL', 'PUBLISHED', 'UNPUBLISHED', 'ARCHIVED', 'NONE')
+ * @param string $filter_entity the entity filter ('ALL', 'ARTICLE', 'CATEGORY')
+ *
+ * @return an array of where clauses
+ */
+ public function getParentPublishedFilter($parent_state, $filter_entity)
+ {
+ // If we want all attachments, do no filtering
+ if ($parent_state == 'ALL')
+ {
+ return array();
+ }
+
+ $db = JFactory::getDBO();
+
+ $where = Array();
+
+ $filter_entity = JString::strtoupper($filter_entity);
+
+ // NOTE: These WHERE clauses will be combined by OR
+
+ if ($parent_state == 'PUBLISHED')
+ {
+
+ if (($filter_entity == 'ALL') || ($filter_entity == 'ARTICLE'))
+ {
+ $now = JFactory::getDate()->toSql();
+ $nullDate = $db->getNullDate();
+ $where[] = "EXISTS (SELECT * FROM #__content AS c1 " .
+ "WHERE (a.parent_entity = 'article' AND c1.id = a.parent_id AND c1.state=1 AND " .
+ '(c1.publish_up = ' . $db->quote($nullDate) . ' OR c1.publish_up <= ' . $db->quote($now) . ') AND ' .
+ '(c1.publish_down = ' . $db->quote($nullDate) . ' OR c1.publish_down >= ' . $db->quote($now) . ')))';
+ }
+
+ if (($filter_entity == 'ALL') || ($filter_entity == 'CATEGORY'))
+ {
+ $where[] = "EXISTS (SELECT * FROM #__categories AS c2 " .
+ "WHERE (a.parent_entity = 'category' AND c2.id = a.parent_id AND c2.published=1))";
+ }
+ }
+ elseif ($parent_state == 'UNPUBLISHED')
+ {
+ // These WHERE clauses will be combined by OR
+ if (($filter_entity == 'ALL') || ($filter_entity == 'ARTICLE'))
+ {
+ $where[] = "EXISTS (SELECT * FROM #__content AS c1 " .
+ "WHERE (a.parent_entity = 'article' AND c1.id = a.parent_id AND c1.state=0))";
+ $where[] = "(a.parent_entity = 'article' AND NOT EXISTS (select * from #__content as c1 where c1.id = a.parent_id))";
+
+ // ??? Add clauses here to get articles that are unpublished because of publish_up/publish_down
+ }
+
+ if (($filter_entity == 'ALL') || ($filter_entity == 'CATEGORY'))
+ {
+ $where[] = "EXISTS (SELECT * FROM #__categories AS c2 " .
+ "WHERE (a.parent_entity = 'category' AND c2.id = a.parent_id AND c2.published=0))";
+ $where[] = "(a.parent_entity = 'category' AND NOT EXISTS (select * from #__categories as c1 where c1.id = a.parent_id))";
+ }
+ }
+ elseif ($parent_state == 'ARCHIVED')
+ {
+ // These WHERE clauses will be combined by OR
+ if (($filter_entity == 'ALL') || ($filter_entity == 'ARTICLE'))
+ {
+ $where[] = "EXISTS (SELECT * FROM #__content AS c1 " .
+ "WHERE (a.parent_entity = 'article' AND c1.id = a.parent_id AND c1.state=2))";
+ }
+
+ if (($filter_entity == 'ALL') || ($filter_entity == 'CATEGORY'))
+ {
+ $where[] = "EXISTS (SELECT * FROM #__categories AS c2 " .
+ "WHERE (a.parent_entity = 'category' AND c2.id = a.parent_id AND c2.published=2))";
+ }
+ }
+ elseif ($parent_state == 'TRASHED')
+ {
+ // These WHERE clauses will be combined by OR
+ if (($filter_entity == 'ALL') || ($filter_entity == 'ARTICLE'))
+ {
+ $where[] = "EXISTS (SELECT * FROM #__content AS c1 " .
+ "WHERE (a.parent_entity = 'article' AND c1.id = a.parent_id AND c1.state=-2))";
+ }
+
+ if (($filter_entity == 'ALL') || ($filter_entity == 'CATEGORY'))
+ {
+ $where[] = "EXISTS (SELECT * FROM #__categories AS c2 " .
+ "WHERE (a.parent_entity = 'category' AND c2.id = a.parent_id AND c2.published=-2))";
+ }
+ }
+ elseif ($parent_state == 'NONE')
+ {
+ // NOTE: The 'NONE' clauses will be combined with AND (with other tests for a.parent_id)
+ $where[] = "(NOT EXISTS( SELECT * FROM #__content as c1 " .
+ "WHERE a.parent_entity = 'article' AND c1.id = a.parent_id ))";
+
+ $where[] = "(NOT EXISTS( SELECT * FROM #__categories as c2 " .
+ "WHERE a.parent_entity = 'category' AND c2.id = a.parent_id ))";
+ }
+ else
+ {
+ $errmsg = JText::sprintf('ATTACH_ERROR_UNRECOGNIZED_PARENT_STATE_S', $parent_state) . ' (ERR 407)';
+ JError::raiseError(500, $errmsg);
+ }
+
+ return $where;
+ }
+
+ /**
+ * May the parent be viewed by the user?
+ *
+ * @param int $parent_id the ID for this parent object
+ * @param string $parent_entity the type of entity for this parent type
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if the parent may be viewed by the user
+ */
+ public function userMayViewParent($parent_id, $parent_entity = 'default', $user_id = null)
+ {
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ // Return the right thing for each entity
+ $table = null;
+ switch ($parent_entity)
+ {
+
+ case 'category':
+ $table = 'categories';
+ break;
+
+ default:
+ // Article
+ $table = 'content';
+ break;
+ }
+
+ // Get the user's permitted access levels
+ $user = JFactory::getUser($user_id);
+ $user_levels = array_unique($user->getAuthorisedViewLevels());
+
+ // See if the parent's access level is permitted for the user
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $query->select('id')->from("#__$table");
+ $query->where('id = ' . (int) $parent_id . ' AND access in (' . implode(',', $user_levels) . ')');
+ $db->setQuery($query, 0, 1);
+ $obj = $db->loadObject();
+ if ($db->getErrorNum())
+ {
+ $parent_entity_name = JText::_('ATTACH_' . $parent_entity);
+ $errmsg = JText::sprintf('ATTACH_ERROR_INVALID_PARENT_S_ID_N', $parent_entity_name, $parent_id) . ' (ERR 408)';
+ JError::raiseError(500, $errmsg);
+ }
+
+ return !empty($obj);
+ }
+
+ /** Return true if the attachments should be hidden for this parent
+ *
+ * @param &object &$parent the object for the parent that onPrepareContent gives
+ * @param int $parent_id the ID of the parent the attachment is attached to
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return true if the attachments should be hidden for this parent
+ */
+ public function attachmentsHiddenForParent(&$parent, $parent_id, $parent_entity)
+ {
+ // Check for generic options
+ if (parent::attachmentsHiddenForParent($parent, $parent_id, $parent_entity))
+ {
+ return true;
+ }
+ $pclass = get_class($parent);
+
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+ $parent_entity_name = JText::_('ATTACH_' . $parent_entity);
+
+ // Make sure we have a valid parent ID
+ if (!$parent_id && ($parent_entity == 'category'))
+ {
+ $parent_id = JRequest::getInt('id');
+ }
+ if ($parent_id !== 0)
+ {
+ // Note: parent_id of 0 may be allowed for categories, so don't abort
+ if (($parent_id == null) || ($parent_id == '') || !is_numeric($parent_id))
+ {
+ $errmsg = JText::sprintf('ATTACH_ERROR_BAD_ENTITY_S_ID', $parent_entity_name) . ' (ERR 409)';
+ JError::raiseError(500, $errmsg);
+ }
+ }
+
+ // Check to see if it should be hidden with readmore
+ $aparams = $this->attachmentsParams();
+ $hide_with_readmore = $aparams->get('hide_with_readmore', false);
+ if ($hide_with_readmore && isset($parent->readmore) && $parent->readmore)
+ {
+ return true;
+ }
+
+ // Get the options
+ $all_but_article_views = $aparams->get('hide_except_article_views', false);
+
+ // Make sure the parent is valid and get info about it
+ $db = JFactory::getDBO();
+
+ if ($parent_entity == 'category')
+ {
+ // Handle categories
+ $always_show_category_attachments = $aparams->get('always_show_category_attachments', false);
+ if ($always_show_category_attachments)
+ {
+ return false;
+ }
+ if ($all_but_article_views)
+ {
+ return true;
+ }
+
+ // Check to see whether the attachments should be hidden for this category
+ $hide_attachments_for_categories = $aparams->get('hide_attachments_for_categories', Array());
+ if (in_array($parent_id, $hide_attachments_for_categories))
+ {
+ return true;
+ }
+
+ // Make sure a category with this ID exists
+ $query = $db->getQuery(true);
+ $query->select('id')->from('#__categories');
+ $query->where('id = ' . (int) $parent_id);
+ $db->setQuery($query, 0, 1);
+ $result = (int) $db->loadResult();
+ if ((int) $parent_id != $result)
+ {
+ return true;
+ }
+ }
+
+ else
+ {
+ // Handle articles
+ if ($parent_id == 0)
+ {
+ return false;
+ }
+
+ // Make sure we have a valid article
+ $query = $db->getQuery(true);
+ $query->select('created_by, catid')->from('#__content')->where('id = ' . (int) $parent_id);
+ $db->setQuery($query);
+ $attachments = $db->loadObjectList();
+ if ($db->getErrorNum() || (count($attachments) === false))
+ {
+ $errmsg = JText::sprintf('ATTACH_ERROR_INVALID_PARENT_S_ID_N', $parent_entity_name, $parent_id) . ' (ERR 410)';
+ JError::raiseError(500, $errmsg);
+ }
+
+ // Honor all_but_article_view option
+ $view = JRequest::getCmd('view');
+ if ($all_but_article_views)
+ {
+ if ($view != 'article')
+ {
+ return true;
+ }
+ }
+
+ // See if the options apply to this article
+ $created_by = (int) $attachments[0]->created_by;
+ $catid = (int) $attachments[0]->catid;
+
+ // First, check to see whether the attachments should be hidden for this parent
+ $hide_attachments_for_categories = $aparams->get('hide_attachments_for_categories', Array());
+ if (in_array($catid, $hide_attachments_for_categories))
+ {
+ return true;
+ }
+ }
+
+ // The default is: attachments are not hidden
+ return false;
+ }
+
+ /**
+ * Return true if the user may add an attachment to this parent
+ *
+ * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
+ * It is up to the caller to validate these objects before calling this function.)
+ *
+ * @param int $parent_id the ID of the parent the attachment is attached to
+ * @param string $parent_entity the type of entity for this parent type
+ * @param bool $new_parent if true, the parent is being created and does not exist yet
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if this user may add attachments to this parent
+ */
+ public function userMayAddAttachment($parent_id, $parent_entity, $new_parent = false, $user_id = null)
+ {
+ require_once JPATH_ADMINISTRATOR . '/components/com_attachments/permissions.php';
+
+ $user = JFactory::getUser($user_id);
+
+ // Handle each entity type
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ switch ($parent_entity)
+ {
+
+ case 'category':
+
+ // First, determine if the user can edit this category
+ if (!AttachmentsPermissions::userMayEditCategory($parent_id))
+ {
+ return false;
+ }
+
+ // Finally, see if the user has permissions to create attachments
+ return $user->authorise('core.create', 'com_attachments');
+
+ break;
+
+ default:
+ // For articles
+
+ // First, determine if the user can edit this article
+ if (!AttachmentsPermissions::userMayEditArticle($parent_id))
+ {
+ return false;
+ }
+
+ // Finally, see if the user has permissions to create attachments
+ return $user->authorise('core.create', 'com_attachments');
+ }
+
+ // No one else is allowed to add attachments
+ return false;
+ }
+
+ /**
+ * Return true if this user may edit (modify/update/delete) this attachment for this parent
+ *
+ * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
+ * It is up to the caller to validate these objects before calling this function.)
+ *
+ * @param &record &$attachment database reocrd for the attachment
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if this user may edit this attachment
+ */
+ public function userMayEditAttachment(&$attachment, $user_id = null)
+ {
+ // If the user generally has permissions to edit all content, they
+ // may edit this attachment (editor, publisher, admin, etc)
+ $user = JFactory::getUser($user_id);
+ if ($user->authorise('com_content', 'edit', 'content', 'all'))
+ {
+ return true;
+ }
+
+ require_once JPATH_ADMINISTRATOR . '/components/com_attachments/permissions.php';
+
+ // Handle each entity type
+
+ switch ($attachment->parent_entity)
+ {
+
+ case 'category':
+
+ // ?? Deal with parents being created (parent_id == 0)
+
+ // First, determine if the user can edit this category
+ if (!AttachmentsPermissions::userMayEditCategory($attachment->parent_id))
+ {
+ return false;
+ }
+
+ // See if the user can edit any attachment
+ if ($user->authorise('core.edit', 'com_attachments'))
+ {
+ return true;
+ }
+
+ // See if the user has permissions to edit their own attachments
+ if ($user->authorise('core.edit.own', 'com_attachments') && ((int) $user->id == (int) $attachment->created_by))
+ {
+ return true;
+ }
+
+ // See if the user has permission to edit attachments on their own cateogory
+ if ($user->authorise('attachments.edit.ownparent', 'com_attachments'))
+ {
+ $category_creator_id = $this->getParentCreatorId($attachment->parent_id, 'category');
+ return (int) $user->id == (int) $category_creator_id;
+ }
+
+ break;
+
+ default:
+ // Articles
+
+ // ?? Deal with parents being created (parent_id == 0)
+
+ // First, determine if the user can edit this article
+ if (!AttachmentsPermissions::userMayEditArticle($attachment->parent_id))
+ {
+ return false;
+ }
+
+ // See if the user can edit any attachment
+ if ($user->authorise('core.edit', 'com_attachments'))
+ {
+ return true;
+ }
+
+ // See if the user has permissions to edit their own attachments
+ if ($user->authorise('core.edit.own', 'com_attachments') && ((int) $user->id == (int) $attachment->created_by))
+ {
+ return true;
+ }
+
+ // See if the user has permission to edit attachments on their own article
+ if ($user->authorise('attachments.edit.ownparent', 'com_attachments'))
+ {
+ $article_creator_id = $this->getParentCreatorId($attachment->parent_id, 'article');
+ return (int) $user->id == (int) $article_creator_id;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Return true if this user may delete this attachment for this parent
+ *
+ * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
+ * It is up to the caller to validate the arguments before calling this function.)
+ *
+ * @param &record &$attachment database record for the attachment
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if this user may delete this attachment
+ */
+ public function userMayDeleteAttachment(&$attachment, $user_id = null)
+ {
+ // If the user generally has permissions to edit ALL content, they
+ // may edit this attachment (editor, publisher, admin, etc)
+ $user = JFactory::getUser($user_id);
+ if ($user->authorise('com_content', 'edit', 'content', 'all'))
+ {
+ return true;
+ }
+
+ require_once JPATH_ADMINISTRATOR . '/components/com_attachments/permissions.php';
+
+ // Handle each entity type
+
+ switch ($attachment->parent_entity)
+ {
+
+ case 'category':
+
+ // First, determine if the user can edit this category
+ if (!AttachmentsPermissions::userMayEditCategory($attachment->parent_id))
+ {
+ return false;
+ }
+
+ // Ok if the user can delete any attachment
+ if ($user->authorise('core.delete', 'com_attachments'))
+ {
+ return true;
+ }
+
+ // See if the user has edit.own and created it
+ if ($user->authorise('attachments.delete.own', 'com_attachments') && ((int) $user->id == (int) $attachment->created_by))
+ {
+ return true;
+ }
+
+ // See if the user has permission to delete any attachments for categories they created
+ if ($user->authorise('attachments.delete.ownparent', 'com_attachments'))
+ {
+ $category_creator_id = $this->getParentCreatorId($attachment->parent_id, 'category');
+ return (int) $user->id == (int) $category_creator_id;
+ }
+
+ break;
+
+ default: // Articles
+
+ // ?? Deal with parents being created (parent_id == 0)
+
+ // First, determine if the user can edit this article
+ if (!AttachmentsPermissions::userMayEditArticle($attachment->parent_id))
+ {
+ return false;
+ }
+
+ // Ok if the user can delete any attachment
+ if ($user->authorise('core.delete', 'com_attachments'))
+ {
+ return true;
+ }
+
+ // See if the user has permissions to delete their own attachments
+ if ($user->authorise('attachments.delete.own', 'com_attachments') && ((int) $user->id == (int) $attachment->created_by))
+ {
+ return true;
+ }
+
+ // See if the user has permission to delete any attachments for articles they created
+ if ($user->authorise('attachments.delete.ownparent', 'com_attachments'))
+ {
+ $article_creator_id = $this->getParentCreatorId($attachment->parent_id, 'article');
+ return (int) $user->id == (int) $article_creator_id;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Return true if this user may change the state of this attachment
+ *
+ * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
+ * It is up to the caller to validate the arguments before calling this function.)
+ *
+ * @param int $parent_id the ID for the parent object
+ * @param string $parent_entity the type of entity for this parent type
+ * @param int $attachment_creator_id the ID of the creator of the attachment
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if this user may change the state of this attachment
+ */
+ public function userMayChangeAttachmentState($parent_id, $parent_entity, $attachment_creator_id, $user_id = null)
+ {
+ // If the user generally has permissions to edit all content, they
+ // may change this attachment state (editor, publisher, admin, etc)
+ $user = JFactory::getUser($user_id);
+ if ($user->authorise('com_content', 'edit', 'content', 'all'))
+ {
+ return true;
+ }
+
+ require_once JPATH_ADMINISTRATOR . '/components/com_attachments/permissions.php';
+
+ // Handle each entity type
+
+ switch ($parent_entity)
+ {
+
+ case 'category':
+
+ // ?? Deal with parents being created (parent_id == 0)
+
+ // First, determine if the user can edit this category
+ if (!AttachmentsPermissions::userMayEditCategory($parent_id))
+ {
+ return false;
+ }
+
+ // See if the user can change the state of any attachment
+ if ($user->authorise('core.edit.state', 'com_attachments'))
+ {
+ return true;
+ }
+
+ // See if the user has permissions to change the state of their own attachments
+ if ($user->authorise('attachments.edit.state.own', 'com_attachments') && ((int) $user->id == (int) $attachment_creator_id))
+ {
+ return true;
+ }
+
+ // See if the user has permission to change the state of any attachments for categories they created
+ if ($user->authorise('attachments.edit.state.ownparent', 'com_attachments'))
+ {
+ $category_creator_id = $this->getParentCreatorId($parent_id, 'category');
+ return (int) $user->id == (int) $category_creator_id;
+ }
+
+ break;
+
+ default:
+ // Articles
+
+ // ?? Deal with parents being created (parent_id == 0)
+
+ // First, determine if the user can edit this article
+ if (!AttachmentsPermissions::userMayEditArticle($parent_id))
+ {
+ return false;
+ }
+
+ // See if the user can change the state of any attachment
+ if ($user->authorise('core.edit.state', 'com_attachments'))
+ {
+ return true;
+ }
+
+ // See if the user has permissions to change the state of their own attachments
+ if ($user->authorise('attachments.edit.state.own', 'com_attachments') && ((int) $user->id == (int) $attachment_creator_id))
+ {
+ return true;
+ }
+
+ // See if the user has permission to edit the state of any attachments for articles they created
+ if ($user->authorise('attachments.edit.state.ownparent', 'com_attachments'))
+ {
+ $article_creator_id = $this->getParentCreatorId($parent_id, 'article');
+ return (int) $user->id == (int) $article_creator_id;
+ }
+ }
+
+ return false;
+ }
+
+ /** Check to see if the user may access (see/download) the attachments
+ *
+ * @param &record &$attachment database record for the attachment
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if access is okay (false if not)
+ */
+ public function userMayAccessAttachment(&$attachment, $user_id = null)
+ {
+ $user = JFactory::getUser($user_id);
+ return in_array($attachment->access, $user->getAuthorisedViewLevels());
+ }
+
+
+ /** See if the attachments list should be displayed in its content description editor
+ *
+ * @param string $parent_entity the type of entity for this parent type
+ * @param string $view the view
+ * @param string $layout the layout on the view
+ *
+ * @return true if the attachments list should be added to the editor
+ */
+ public function showAttachmentsInEditor($parent_entity, $view, $layout)
+ {
+ return ($layout =='edit') && (($view == 'form') || ($view == 'article') || ($view == 'category'));
+ }
+
+ /** Get the parent_id in the component content item editor
+ * (the article or category editor)
+ *
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return the parent ID, null if the content item is being created, and false if there is no match
+ *
+ * @since Attachments 3.2
+ */
+ public function getParentIdInEditor($parent_entity, $view, $layout)
+ {
+ $app = JFactory::getApplication();
+ if ($app->isAdmin()) {
+ // The default works fine for the back end
+ return parent::getParentIdInEditor($parent_entity, $view, $layout);
+ }
+
+ // Note categories cannot be created or edited from the frontend
+ if ($parent_entity == 'category') {
+ return false;
+ }
+
+ // Deal with articles (in frontend)
+ $id = null;
+ if (($view == 'article') OR ($view == 'form')) {
+ $id = JRequest::getInt('a_id', $default=null);
+ }
+ else {
+ $id = false;
+ }
+
+ // If we got one, convert it to an int
+ if (is_numeric($id)) {
+ $id = (int)$id;
+ }
+
+ return $id;
+ }
+
+
+ /** Known from keywords
+ *
+ * Attachment pop-dialogs will be closed using javascript if they are called from pages of these 'from' types
+ *
+ * @retrun array An array of known tokens (strings)
+ */
+ public function knownFroms()
+ {
+ return array_merge(parent::knownFroms(), Array('frontpage', 'featured', 'article', 'category', 'details'));
+ }
+
+}
+
+
+/** Register this attachments type */
+$apm = getAttachmentsPluginManager();
+$apm->addParentType('com_content');
diff --git a/plugins/attachments/attachments_for_content/attachments_for_content.xml b/plugins/attachments/attachments_for_content/attachments_for_content.xml
new file mode 100644
index 00000000..29d21dfb
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/attachments_for_content.xml
@@ -0,0 +1,21 @@
+
+
+ plg_attachments_for_content
+ 3.2.6
+ March 26, 2018
+ Jonathan M. Cameron
+ jmcameron@jmcameron.net
+ http://joomlacode.org/gf/project/attachments/
+ (C) 2009-2018 Jonathan M. Cameron. All rights reserved.
+ http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ ATTACH_ATTACHMENTS_FOR_CONTENT_PLUGIN_DESCRIPTION
+
+ install.php
+
+
+ attachments_for_content.php
+ index.html
+ language
+
+
+
diff --git a/plugins/attachments/attachments_for_content/index.html b/plugins/attachments/attachments_for_content/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/attachments/attachments_for_content/install.php b/plugins/attachments/attachments_for_content/install.php
new file mode 100644
index 00000000..9a71e972
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/install.php
@@ -0,0 +1,61 @@
+getQuery(true);
+ $query->update('#__extensions')
+ ->set("enabled = 0")
+ ->where('type=' . $db->quote('plugin') . ' AND name=' . $db->quote($plugin_name));
+ $db->setQuery($query);
+ $db->query();
+
+ // NOTE: Do NOT complain if there was an error
+ // (in case any plugin is already uninstalled and this query fails)
+ }
+ }
+
+}
diff --git a/plugins/attachments/attachments_for_content/language/en-GB/en-GB.plg_attachments_attachments_for_content.ini b/plugins/attachments/attachments_for_content/language/en-GB/en-GB.plg_attachments_attachments_for_content.ini
new file mode 100644
index 00000000..a51baf55
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/language/en-GB/en-GB.plg_attachments_attachments_for_content.ini
@@ -0,0 +1,14 @@
+; en-GB.plg_attachments_for_content.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+ATTACH_ARTICLE="Article"
+ATTACH_ARTICLES="Articles"
+ATTACH_ATTACHMENTS_FOR_CONTENT_PLUGIN_DESCRIPTION="The Attachments for Content plugin enables adding attachments to content articles as well as category descriptions."
+ATTACH_CATEGORY="Category"
+ATTACH_CATEGORYS="Categories"
+ATTACH_ERROR_UNRECOGNIZED_PARENT_STATE_S="ERROR: Unrecognized parent state (%s)"
diff --git a/plugins/attachments/attachments_for_content/language/en-GB/en-GB.plg_attachments_attachments_for_content.sys.ini b/plugins/attachments/attachments_for_content/language/en-GB/en-GB.plg_attachments_attachments_for_content.sys.ini
new file mode 100644
index 00000000..bf8004b4
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/language/en-GB/en-GB.plg_attachments_attachments_for_content.sys.ini
@@ -0,0 +1,10 @@
+; en-GB.plg_attachments_for_content.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+ATTACH_ATTACHMENTS_FOR_CONTENT_PLUGIN_DESCRIPTION="The Attachments for Content plugin enables adding attachments to content articles as well as category descriptions."
+PLG_ATTACHMENTS_FOR_CONTENT="Attachments - For Content"
diff --git a/plugins/attachments/attachments_for_content/language/en-GB/index.html b/plugins/attachments/attachments_for_content/language/en-GB/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/language/en-GB/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/attachments/attachments_for_content/language/index.html b/plugins/attachments/attachments_for_content/language/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/language/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/attachments/attachments_for_content/language/it-IT/index.html b/plugins/attachments/attachments_for_content/language/it-IT/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/language/it-IT/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/attachments/attachments_for_content/language/it-IT/it-IT.plg_attachments_attachments_for_content.ini b/plugins/attachments/attachments_for_content/language/it-IT/it-IT.plg_attachments_attachments_for_content.ini
new file mode 100644
index 00000000..0014089d
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/language/it-IT/it-IT.plg_attachments_attachments_for_content.ini
@@ -0,0 +1,14 @@
+; it-IT.plg_attachments_for_content.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2013 Jonathan M. Cameron, All rights reserved.
+; License GNU GPL 3: http://www.gnu.org/licenses/gpl-3.0.html
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0, 3.0), Lemminkainen (version 1.3.4)
+
+ATTACH_ARTICLE="Articolo"
+ATTACH_ARTICLES="Articoli"
+ATTACH_ATTACHMENTS_FOR_CONTENT_PLUGIN_DESCRIPTION="Questo plugin permette di aggiungere allegati agli articoli, come pure alle descrizioni di categorie."
+ATTACH_CATEGORY="Categoria"
+ATTACH_CATEGORYS="Categorie"
+ATTACH_ERROR_UNRECOGNIZED_PARENT_STATE_S="ERROR: Stato del genitore non riconosciuto(%s)"
diff --git a/plugins/attachments/attachments_for_content/language/it-IT/it-IT.plg_attachments_attachments_for_content.sys.ini b/plugins/attachments/attachments_for_content/language/it-IT/it-IT.plg_attachments_attachments_for_content.sys.ini
new file mode 100644
index 00000000..706ee1af
--- /dev/null
+++ b/plugins/attachments/attachments_for_content/language/it-IT/it-IT.plg_attachments_attachments_for_content.sys.ini
@@ -0,0 +1,10 @@
+; it-IT.plg_attachments_for_content.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2013 Jonathan M. Cameron, All rights reserved.
+; License GNU GPL 3: http://www.gnu.org/licenses/gpl-3.0.html
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0, 3.0), Lemminkainen (version 1.3.4)
+
+ATTACH_ATTACHMENTS_FOR_CONTENT_PLUGIN_DESCRIPTION="Questo plugin permette di aggiungere allegati agli articoli, come pure alle descrizioni di categorie."
+PLG_ATTACHMENTS_FOR_CONTENT="Allegati - Per contenuti"
diff --git a/plugins/attachments/attachments_plugin_framework/attachments_plugin.php b/plugins/attachments/attachments_plugin_framework/attachments_plugin.php
new file mode 100644
index 00000000..38ca6009
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/attachments_plugin.php
@@ -0,0 +1,1098 @@
+
+ * @copyright Copyright (C) 2009-2018 Jonathan M. Cameron, All Rights Reserved
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ * @link http://joomlacode.org/gf/project/attachments/frs/
+ */
+
+// No direct access
+defined('_JEXEC') or die('Restricted access');
+
+/** Load the attachments helper */
+require_once JPATH_SITE . '/components/com_attachments/helper.php';
+
+
+/**
+ * Plugins for Attachments
+ *
+ * AttachmentsPlugin is the base class for all the plugins to allow
+ * attaching files to various types of content entities
+ *
+ * The derived attachments plugin class must be in the main PHP file for that
+ * plugin. For instance for content articles or categories, the parent type
+ * is 'com_content'. The parent type is simply the name of the component
+ * involved (eg, 'com_content'). The derived attachments plugin class (such
+ * as 'AttachmentsPlugin_com_content') should be defined in the main file for
+ * the plugin (eg, attachments_for_conent.php).
+ *
+ * Derived attachments plugin classes must also include the following lines of
+ * code after the class definition to register the derived class with the
+ * Attachments plugin manager:
+ *
+ * $apm = getAttachmentsPluginManager();
+ * $apm->addParentType('com_content');
+ *
+ * where 'com_content' should be replaced by the name of the appropriate
+ * parent type (component).
+ *
+ * @package Attachments
+ * @since 3.0
+ */
+class AttachmentsPlugin extends JPlugin
+{
+ /** Parent_type: com_content, com_quickfaq, etc
+ */
+ protected $parent_type = null;
+
+ /** Name for the default parent_entity type
+ *
+ * Note that this name will be used for a directory for attachments entries
+ * and should not contain any spaces. It should correspond to the default
+ * entity. For instance, for com_content, it will be 'article';
+ */
+ protected $default_entity = null;
+
+ /** known entities
+ */
+ protected $entities = null;
+
+ /** An associative array of entity names
+ *
+ * For each type of attachments plugin, there will be a default
+ * entity types. For com_content, the default is 'article'. If
+ * the $default value for the function calls below is omitted,
+ * the entity is assumed to be 'article'. In some cases, the
+ * actual proper name of the entity will be available and will be
+ * passed in to the $default argument. It is important that the
+ * plugin code recognizes that the entity 'default' is an alias
+ * for 'article'. This array allows a simple associative array
+ * lookup to transform 'default' to 'article'.
+ */
+ protected $entity_name = Array();
+
+ /** An associative array of entity tables
+ */
+ protected $entity_table = Array();
+
+ /** An associative array of entity id fields
+ * (in same table as the title)
+ */
+ protected $entity_id_field = Array();
+
+ /** An associative array of entity title fields
+ */
+ protected $entity_title_field = Array();
+
+ /** An associative array of parent creator user ID fields
+ */
+ protected $parent_creator_id_field = Array();
+
+ /** Flag indicating if the language file haas been loaded
+ */
+ protected $language_loaded = false;
+
+ /** Cache for parentExists check
+ */
+ protected $parent_exists_cache = Array();
+
+ /** Cache for parent titles
+ */
+ protected $title_cache = Array();
+
+ /** Cache for parameters for the com_attachments component
+ */
+ private $com_attachments_params = null;
+
+ /**
+ * Constructor
+ *
+ * @param object &$subject The object to observe
+ * @param array $config An optional associative array of configuration settings.
+ * Recognized key values include 'name', 'group', 'params', 'language'
+ * (this list is not meant to be comprehensive).
+ */
+ public function __construct(&$subject, $config = array())
+ {
+ parent::__construct($subject, $config);
+
+ // Save the plugin type
+ $this->_type = 'attachments';
+ }
+
+ /**
+ * Get the attachments parameter object
+ *
+ * @return object com_attachments parameter object
+ */
+ public function attachmentsParams()
+ {
+ if ($this->com_attachments_params == null)
+ {
+ jimport('joomla.application.component.helper');
+ $this->com_attachments_params = JComponentHelper::getParams('com_attachments');
+ }
+
+ return $this->com_attachments_params;
+ }
+
+ /**
+ * Return the parent entity / row ID
+ *
+ * This will only be called by the main attachments 'onPrepareContent'
+ * plugin if $attachment ($row) does not have an id
+ *
+ * @param object &$attachment the attachment
+ *
+ * @return id if found, false if this is not a valid parent
+ */
+ public function getParentId(&$attachment)
+ {
+ return JRequest::getInt('id', false);
+ }
+
+ /**
+ * Return the component name for this parent object
+ *
+ * @return the component name for this parent object
+ */
+ public function getParentType()
+ {
+ return $this->parent_type;
+ }
+
+ /**
+ * Return a string of the where clause for filtering the the backend list of attachments
+ *
+ * @param string $parent_state the state ('ALL', 'PUBLISHED', 'UNPUBLISHED', 'ARCHIVED', 'NONE')
+ * @param string $filter_entity the entity filter ('ALL', 'ARTICLE', 'CATEGORY', etc)
+ *
+ * @return an array of (join_clause, where_clause) items
+ */
+ public function getParentPublishedFilter($parent_state, $filter_entity)
+ {
+ return array();
+ }
+
+ /**
+ * Determine the parent entity
+ *
+ * From the view and the class of the parent (row of onPrepareContent plugin),
+ * determine what the entity type is for this entity.
+ *
+ * Derived classes MUST overrride this
+ *
+ * @param &object &$parent The object for the parent (row) that onPrepareContent gets
+ *
+ * @return the correct entity (eg, 'default', 'category', etc) or false if this entity should not be displayed.
+ */
+ public function determineParentEntity(&$parent)
+ {
+ return 'default';
+ }
+
+ /**
+ * Return the name of the field with the content item text
+ *
+ * During the display of content items (eg, articles, categories), the
+ * onContentPrepare (etc) callbacks are used to insert attachments lists.
+ * The second argument of the onContentPrepare() function is an object
+ * (usually $row) for the content item (eg, article). This function will
+ * return the appropriate field for the text of the content item. In some
+ * cases it is 'text', in others, 'introtext'. Attachments plugins can
+ * override this function to provide the field name more intelligently.
+ *
+ * Note: returns null if the text field is unknown/not present.
+ *
+ * @param &object &$row the content object (eg, article) being displayed
+ * @param string $parent_entity the type of entity for this content item.
+ *
+ * @return string name of the text field of this content item object.
+ */
+ protected function getTextFieldName(&$row, $parent_entity)
+ {
+ $text_field_name = null;
+
+ // Ignore items without the normal 'text' field
+ if (isset($row->text))
+ {
+ $text_field_name = 'text';
+ }
+ elseif (isset($row->fulltext))
+ {
+ $text_field_name = 'fulltext';
+ }
+ elseif (isset($row->introtext))
+ {
+ $text_field_name = 'introtext';
+ }
+
+ return $text_field_name;
+ }
+
+ /**
+ * Return the array of entity IDs for all content items supported by this parent object
+ *
+ * @return the array of entities supported by this parent object
+ */
+ public function getEntities()
+ {
+ return $this->entities;
+ }
+
+ /**
+ * Get the default entity ID
+ *
+ * @return string the default entity ID
+ */
+ public function getDefaultEntity()
+ {
+ return $this->default_entity;
+ }
+
+ /**
+ * Get the canonical extension entity Id (eg, 'article' instead of 'default')
+ *
+ * This is the canonical Id of content element/item to which attachments will be added.
+ *
+ * that each content type ($option) may support several different entities
+ * (for attachments) and some entities may have more than one name.
+ *
+ * Note, for com_content, the default is 'article'
+ *
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return the canonical extension entity
+ */
+ public function getCanonicalEntityId($parent_entity)
+ {
+ // It it is a known entity, just return it
+ if (is_array($this->entities) && in_array($parent_entity, $this->entities))
+ {
+ return $parent_entity;
+ }
+
+ // Check aliases
+ if (is_array($this->entities) && array_key_exists($parent_entity, $this->entity_name))
+ {
+ return $this->entity_name[$parent_entity];
+ }
+ else
+ {
+ $lang = JFactory::getLanguage();
+ $lang->load('plg_attachments_attachments_plugin_framework', dirname(__FILE__));
+ $errmsg = JText::sprintf('ATTACH_ERROR_INVALID_ENTITY_S_FOR_PARENT_S', $parent_entity, $this->parent_type) . ' (ERR 300)';
+ JError::raiseError(500, $errmsg);
+ }
+ }
+
+ /**
+ * Get the path for the uploaded file (on the server file system)
+ *
+ * Note that this does not include the base directory for attachments.
+ *
+ * @param string $parent_entity the type of entity for this parent type
+ * @param int $parent_id the ID for the parent object
+ * @param int $attachment_id the ID for the attachment
+ *
+ * @return string the directory name for this entity (with trailing '/'!)
+ */
+ public function getAttachmentPath($parent_entity, $parent_id, $attachment_id)
+ {
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ $path = sprintf("%s/%d/", $parent_entity, $parent_id);
+
+ return $path;
+ }
+
+ /**
+ * Get the name or title for the specified object
+ *
+ * @param int $parent_id the ID for this parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return the name or title for the specified object
+ */
+ public function getTitle($parent_id, $parent_entity = 'default')
+ {
+ // Short-circuit if there is no parent ID
+ if (!is_numeric($parent_id))
+ {
+ return '';
+ }
+
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ // Check the cache first
+ $cache_key = $parent_entity . (int) $parent_id;
+ if (array_key_exists($cache_key, $this->title_cache))
+ {
+ return $this->title_cache[$cache_key];
+ }
+
+ $entity_table = $this->entity_table[$parent_entity];
+ $entity_title_field = $this->entity_title_field[$parent_entity];
+ $entity_id_field = $this->entity_id_field[$parent_entity];
+
+ // Make sure the parent exists
+ if (!$this->parentExists($parent_id, $parent_entity))
+ {
+ /* Do not error out; this is most likely to occur in the backend
+ * when an article with attachments has been deleted without
+ * deleting the attachments. But we still need list it!
+ */
+ return '';
+ }
+
+ // Look up the title
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $query->select($entity_title_field)->from("#__$entity_table");
+ $query->where("$entity_id_field=" . (int) $parent_id);
+ $db->setQuery($query);
+ $title = $db->loadResult();
+ if ($db->getErrorNum())
+ {
+ $parent_entity_name = JText::_('ATTACH_' . $parent_entity);
+ $errmsg = JText::sprintf('ATTACH_ERROR_GETTING_PARENT_S_TITLE_FOR_ID_N',
+ $parent_entity_name, $parent_id) . ' (ERR 301)';
+ JError::raiseError(500, $errmsg);
+ }
+
+ $this->title_cache[$cache_key] = $title;
+
+ return $this->title_cache[$cache_key];
+ }
+
+ /**
+ * Return an array of entity items (with id,title pairs for each item)
+ *
+ * @param string $parent_entity the type of entity to search for
+ * @param string $filter filter the results for matches for this filter string
+ *
+ * @return the array of entity id,title pairs
+ */
+ public function getEntityItems($parent_entity = 'default', $filter = '')
+ {
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ $entity_table = $this->entity_table[$parent_entity];
+ $entity_title_field = $this->entity_title_field[$parent_entity];
+ $entity_id_field = $this->entity_id_field[$parent_entity];
+
+ // Get the ordering information
+ $app = JFactory::getApplication();
+ $order = $app->getUserStateFromRequest('com_attachments.selectEntity.filter_order',
+ 'filter_order', '', 'cmd');
+ $order_Dir = $app->getUserStateFromRequest('com_attachments.selectEntity.filter_order_Dir',
+ 'filter_order_Dir', '', 'word');
+
+ // Get all the items
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $query->select("DISTINCT $entity_id_field,$entity_title_field");
+ $query->from("#__$entity_table");
+ if ($filter)
+ {
+ $filter = $db->quote('%' . $db->escape($filter, true) . '%', false);
+ $query->where($entity_title_field . ' LIKE ' . $filter);
+ }
+
+ if ($order)
+ {
+ if ($order == 'title')
+ {
+ $query->order("$entity_title_field " . $order_Dir);
+ }
+ elseif ($order == 'id')
+ {
+ $query->order("$entity_id_field " . $order_Dir);
+ }
+ else
+ {
+ // Ignore unrecognized columns
+ }
+ }
+
+ // Do the query
+ $db->setQuery($query);
+ if ($db->getErrorNum())
+ {
+ $parent_entity_name = JText::_('ATTACH_' . $parent_entity);
+ $errmsg = JText::sprintf('ATTACH_ERROR_GETTING_LIST_OF_ENTITY_S_ITEMS', $parent_entity_name) . ' (ERR 302)';
+ JError::raiseError(500, $errmsg);
+ }
+ else
+ {
+ $items = $db->loadObjectList();
+ }
+
+ if ($items == null)
+ {
+ return null;
+ }
+
+ // Make sure the the ids are called 'id' in the list
+ if ($entity_id_field != 'id')
+ {
+ foreach ($items as $item)
+ {
+ $item->id = $item->$entity_id_field;
+ }
+ }
+
+ // Make sure the the titles are called 'title' in the list
+ if ($entity_title_field != 'title')
+ {
+ foreach ($items as $item)
+ {
+ $item->title = $item->$entity_title_field;
+ }
+ }
+
+ return $items;
+ }
+
+ /**
+ * Return the URL that can be called to select a specific content item.
+ *
+ * @param string $parent_entity the type of entity to select from
+ *
+ * @return the URL that can be called to select a specific content item
+ */
+ public function getSelectEntityURL($parent_entity = 'default')
+ {
+ // Add on the parent type and entity
+ $entity = "&parent_type=" . $this->parent_type;
+
+ if ($parent_entity != 'default')
+ {
+ $entity .= '.' . $parent_entity;
+ }
+
+ return "index.php?option=com_attachments&task=selectEntity" . $entity . "&tmpl=component";
+ }
+
+ /**
+ * Return the ID of the creator/owner of the parent entity
+ *
+ * @param int $parent_id the ID for the parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return creators id if found, 0 otherwise
+ */
+ public function getParentCreatorId($parent_id, $parent_entity = 'default')
+ {
+ JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
+ }
+
+ /**
+ * Get a URL to view the entity
+ *
+ * @param int $parent_id the ID for this parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return a URL to view the entity (non-SEF form)
+ */
+ public function getEntityViewURL($parent_id, $parent_entity = 'default')
+ {
+ return null;
+ }
+
+ /**
+ * Get a URL to add an attachment to a specific entity
+ *
+ * @param int $parent_id the ID for the parent entity object (null if the parent does not exist)
+ * @param string $parent_entity the type of entity for this parent type
+ * @param string $from where the call should return to
+ *
+ * @return the url to add a new attachments to the specified entity
+ */
+ public function getEntityAddUrl($parent_id, $parent_entity = 'default', $from = 'closeme')
+ {
+ $app = JFactory::getApplication();
+
+ if ($app->isAdmin())
+ {
+ $task = 'add';
+ }
+ else
+ {
+ $task = 'upload';
+ }
+
+ $url = "index.php?option=com_attachments&task=$task";
+ if ($parent_id == null)
+ {
+ $url .= "&parent_id=$parent_id,new";
+ }
+ else
+ {
+ $url .= "&parent_id=$parent_id";
+ }
+
+ $url .= "&parent_type=" . $this->parent_type . "&from=$from";
+
+ return $url;
+ }
+
+ /**
+ * Check to see if a custom title applies to this parent
+ *
+ * Note: this public function assumes that the parent_id's match
+ *
+ * @param string $parent_entity the parent entity for the parent of the list
+ * @param string $rtitle_parent_entity the entity of the candidate attachment list title (from params)
+ *
+ * @return true if the custom title should be used
+ */
+ public function checkAttachmentsListTitle($parent_entity, $rtitle_parent_entity)
+ {
+ return false;
+ }
+
+ /**
+ * Get the title for the attachments list for this parent
+ *
+ * @param string $title the untranslated title token (either 'ATTACH_ATTACHMENTS_TITLE' or 'ATTACH_EXISTING_ATTACHMENTS')
+ * @param int $parent_id the ID for the parent entity object (null if the parent does not exist)
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return the translated title string
+ */
+ public function attachmentsListTitle($title, $parent_id, $parent_entity = 'default')
+ {
+ $aparams = $this->attachmentsParams();
+ $rtitle_str = $aparams->get('attachments_titles', '');
+ if (($title != 'ATTACH_EXISTING_ATTACHMENTS') && ($rtitle_str != ''))
+ {
+ $rtitle_list = preg_split("[\n|\r]", $rtitle_str);
+
+ foreach ($rtitle_list as $rtitle)
+ {
+ if (preg_match('|^([0-9]+)\s*([^$]+)$|', $rtitle, $match))
+ {
+ // Process: 3 new title
+ // NOTE: This form only applies to articles and will be ignored for anything else
+ if ((int) $parent_id != (int) $match[1])
+ {
+ continue;
+ }
+
+ if (($this->parent_type == 'com_content') && (($parent_entity == 'default') || ($parent_entity == 'article')))
+ {
+ $title = $match[2];
+ }
+ }
+ elseif (preg_match('|^([a-zA-Z0-9_/-]+):([0-9]+)\s*([^$]+)$|', $rtitle, $match))
+ {
+ // Process: entity:3 new title
+ if ((int) $parent_id != (int) $match[2])
+ {
+ continue;
+ }
+
+ if ($this->checkAttachmentsListTitle($parent_entity, $match[1]))
+ {
+ $title = $match[3];
+ }
+ }
+ else
+ {
+ // With no entity/numeric prefix, the title applies to all attachments lists
+ $rtitle = trim($rtitle);
+ if ($rtitle != '')
+ {
+ $title = $rtitle;
+ }
+ }
+ }
+ }
+
+ return JText::_($title);
+ }
+
+ /**
+ * Does the parent exist?
+ *
+ * @param int $parent_id the ID for this parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return true if the parent exists
+ */
+ public function parentExists($parent_id, $parent_entity = 'default')
+ {
+ $parent_entity = $this->getCanonicalEntityId($parent_entity);
+
+ // Check the cache first
+ $cache_key = $parent_entity . (int) $parent_id;
+ if (array_key_exists($cache_key, $this->parent_exists_cache))
+ {
+ return $this->parent_exists_cache[$cache_key];
+ }
+
+ // First time, so look up the parent
+ $entity_table = $this->entity_table[$parent_entity];
+ $entity_id_field = $this->entity_id_field[$parent_entity];
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $query->select($entity_id_field)->from("#__$entity_table");
+ $query->where("$entity_id_field=" . (int) $parent_id);
+ $db->setQuery($query, 0, 1);
+ $result = $db->loadResult();
+ if ($result === null)
+ {
+ $this->parent_exists_cache[$cache_key] = false;
+ }
+ else
+ {
+ $this->parent_exists_cache[$cache_key] = (int) $parent_id == (int) $result;
+ }
+
+ return $this->parent_exists_cache[$cache_key];
+ }
+
+ /**
+ * Is the parent new (based on the parent_id)
+ *
+ * @param object &$attachment the attachment
+ *
+ * @return true if the parent is new (being created)
+ */
+ public function newParent(&$attachment)
+ {
+ // Assume parent_id == 0 means the parent is new
+ // (NOTE: This may not be true for some components)
+ return $attachment->parent_id == 0;
+ }
+
+
+ /**
+ * Check to see if the parent is published
+ *
+ * @param int $parent_id the ID for this parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return true if the parent is published
+ */
+ public function isParentPublished($parent_id, $parent_entity = 'default')
+ {
+ return false;
+ }
+
+ /**
+ * Check to see if the parent is archived
+ *
+ * @param int $parent_id the ID for this parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return true if the parent is archived
+ */
+ public function isParentArchived($parent_id, $parent_entity = 'default')
+ {
+ return false;
+ }
+
+ /**
+ * May the parent be viewed by the user?
+ *
+ * This public function should be called by derived class functions.
+ *
+ * Note that this base class function only determines necessary
+ * conditions. If this function returns FALSE, then viewing is definitely
+ * not permitted. If this function returns TRUE, then the derived classes
+ * also need to check whether viewing the specific content item (eg,
+ * article) is permitted.
+ *
+ * @param int $parent_id the ID for this parent object
+ * @param string $parent_entity the type of entity for this parent type
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if the parent may be viewed by the user
+ */
+ public function userMayViewParent($parent_id, $parent_entity = 'default', $user_id = null)
+ {
+ JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
+ }
+
+ /** Return true if the attachments should be hidden for this parent
+ *
+ * @param &object &$parent the object for the parent that onPrepareContent gives
+ * @param int $parent_id the ID of the parent the attachment is attached to
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * Note: this generic version only implements the 'frontpage' option. All
+ * other options should be handled by the derived classes for other
+ * content types.
+ *
+ * @return true if the attachments should be hidden for this parent
+ */
+ public function attachmentsHiddenForParent(&$parent, $parent_id, $parent_entity)
+ {
+ $layout = JRequest::getCmd('layout');
+ $aparams = $this->attachmentsParams();
+
+ // Check to see whether the attachments should be hidden on the front page
+ $hide_on_frontpage = $aparams->get('hide_on_frontpage', false);
+ if ($hide_on_frontpage && (JRequest::getVar('view') == 'featured'))
+ {
+ return true;
+ }
+
+ // Hide on blog pages?
+ $hide_on_blogs = $aparams->get('hide_on_blogs', false);
+ if ($hide_on_blogs && ($layout == 'blog'))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Return true if the user may add an attachment to this parent
+ *
+ * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
+ * It is up to the caller to validate these objects before calling this function.)
+ *
+ * @param int $parent_id the ID of the parent the attachment is attached to
+ * @param string $parent_entity the type of entity for this parent type
+ * @param bool $new_parent if true, the parent is being created and does not exist yet
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if this user add attachments to this parent
+ */
+ public function userMayAddAttachment($parent_id, $parent_entity, $new_parent = false, $user_id = null)
+ {
+ JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
+ }
+
+ /**
+ * Return true if this user may edit (modify/delete/update) this attachment for this parent
+ *
+ * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
+ * It is up to the caller to validate the arguments before calling this function.)
+ *
+ * @param &record &$attachment database record for the attachment
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if this user may edit this attachment
+ */
+ public function userMayEditAttachment(&$attachment, $user_id = null)
+ {
+ JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
+ }
+
+ /**
+ * Return true if this user may delete this attachment for this parent
+ *
+ * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
+ * It is up to the caller to validate the arguments before calling this function.)
+ *
+ * @param &record &$attachment database record for the attachment
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if this user may delete this attachment
+ */
+ public function userMayDeleteAttachment(&$attachment, $user_id = null)
+ {
+ JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
+ }
+
+ /**
+ * Return true if this user may change the state of this attachment
+ *
+ * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
+ * It is up to the caller to validate the arguments before calling this function.)
+ *
+ * @param int $parent_id the ID for the parent object
+ * @param string $parent_entity the type of entity for this parent type
+ * @param int $attachment_creator_id the ID of the creator of the attachment
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if this user may change the state of this attachment
+ */
+ public function userMayChangeAttachmentState($parent_id, $parent_entity, $attachment_creator_id, $user_id = null)
+ {
+ JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
+ }
+
+ /** Check to see if the user may access (see/download) the attachments
+ *
+ * @param &record &$attachment database record for the attachment
+ * @param object $user_id the user_id to check (optional, primarily for testing)
+ *
+ * @return true if access is okay (false if not)
+ */
+ public function userMayAccessAttachment(&$attachment, $user_id = null)
+ {
+ JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
+ }
+
+ /** Insert the attachments list into the content text (for front end)
+ *
+ * @param object &$content the text of the content item (eg, article text)
+ * @param int $parent_id the ID for the parent object
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return string the modified content text (false for failure)
+ */
+ public function insertAttachmentsList(&$content, $parent_id, $parent_entity)
+ {
+ $aparams = $this->attachmentsParams();
+
+ // Get the desired placement
+ $attachments_placement = $aparams->get('attachments_placement', 'end');
+ if ($attachments_placement == 'disabled_nofilter')
+ {
+ return false;
+ }
+
+ // Determine where we are
+ $from = JRequest::getCmd('view', 'closeme');
+ $Itemid = JRequest::getInt('Itemid', 1);
+
+ // See whether we can display the links to add attachments
+ $user_can_add = $this->userMayAddAttachment($parent_id, $parent_entity);
+
+ // Get the field name for the content item's text
+ $text_field_name = $this->getTextFieldName($content, $parent_entity);
+ if ($text_field_name === null)
+ {
+ return false;
+ }
+
+ // Get the attachments tag, if present
+ $attachments_tag = '';
+ $attachments_tag_args = '';
+ $match = false;
+ if (JString::strpos($content->$text_field_name, '{attachments'))
+ {
+ if (preg_match('@()?{attachments([ ]*:*[^}]+)?}()?@', $content->$text_field_name, $match))
+ {
+ $attachments_tag = true;
+ }
+
+ if (isset($match[1]) && $match[1])
+ {
+ $attachments_tag_args_raw = $match[1];
+ $attachments_tag_args = ltrim($attachments_tag_args_raw, ' :');
+ }
+
+ if ($attachments_tag)
+ {
+ $attachments_tag = $match[0];
+ }
+ }
+
+ // Check the security status
+ $attach_dir = JPATH_SITE . '/' . AttachmentsDefines::$ATTACHMENTS_SUBDIR;
+ $secure = $aparams->get('secure', false);
+ $hta_filename = $attach_dir . '/ . htaccess';
+ if (($secure && !file_exists($hta_filename)) || (!$secure && file_exists($hta_filename)))
+ {
+ AttachmentsHelper::setup_upload_directory($attach_dir, $secure);
+ }
+
+ // Construct the attachment list (if appropriate)
+ $html = '';
+ $attachments_list = false;
+ $add_attachement_btn = false;
+
+ // Get the html for the attachments list
+ require_once JPATH_SITE . '/components/com_attachments/controllers/attachments.php';
+ $controller = new AttachmentsControllerAttachments;
+ $attachments_list = $controller->displayString($parent_id, $this->parent_type, $parent_entity, null, true, true, false, $from);
+
+ // If the attachments list is empty, insert an empty div for it
+ if ($attachments_list == '')
+ {
+ $class_name = $aparams->get('attachments_table_style', 'attachmentsList');
+ $div_id = 'attachmentsList' . '_' . $this->parent_type . '_' . $parent_entity . '_' . (string) $parent_id;
+ $attachments_list = "\n\n";
+ }
+
+ $html .= $attachments_list;
+
+ if ($html || $user_can_add)
+ {
+ // Add the style sheet
+ JHtml::stylesheet('com_attachments/attachments_list.css', Array(), true);
+
+ // Handle RTL styling (if necessary)
+ $lang = JFactory::getLanguage();
+ if ($lang->isRTL())
+ {
+ JHtml::stylesheet('com_attachments/attachments_list_rtl.css', Array(), true);
+ }
+ }
+
+ // Construct the add-attachments button, if appropriate
+ $hide_add_attachments_link = $aparams->get('hide_add_attachments_link', 0);
+ if ($user_can_add && !$hide_add_attachments_link)
+ {
+ $add_attachments_btn = AttachmentsHelper::attachmentButtonsHTML($this->parent_type, $parent_id, $parent_entity, $Itemid, $from);
+ $html .= $add_attachments_btn;
+ }
+
+ // Wrap both list and the Add Attachments button in another div
+ if ($html)
+ {
+ $html = "
\n" . $html . "\n
";
+ }
+
+ // Finally, add the attachments
+
+ // NOTE: Hope str_replace() below is UTF8 safe (since the token being replaced is UTF8)...
+
+ switch ($attachments_placement)
+ {
+ case 'beginning':
+ // Put the attachments list at the beginning
+ if ($attachments_list || $user_can_add)
+ {
+ if ($attachments_tag)
+ {
+ $content->$text_field_name = $html . $content->$text_field_name;
+ }
+ else
+ {
+ $content->$text_field_name = $html . str_replace($attachments_tag, '', $content->$text_field_name);
+ }
+ }
+ break;
+
+ case 'custom':
+ // Insert the attachments at the desired location
+ if ($attachments_list || $user_can_add)
+ {
+ if ($attachments_tag)
+ {
+ $content->$text_field_name = str_replace($attachments_tag, $html, $content->$text_field_name);
+ }
+ else
+ {
+ // If there is no tag, insert the attachments at the end
+ $content->$text_field_name .= $html;
+ }
+ }
+ break;
+
+ case 'disabled_filter':
+ // Disable and strip out any attachments tags
+ if ($attachments_tag)
+ {
+ $content->$text_field_name = str_replace($attachments_tag, '', $content->$text_field_name);
+ }
+ break;
+
+ default:
+ // Add the attachments to the end
+ if ($attachments_list || $user_can_add)
+ {
+ if ($attachments_tag)
+ {
+ $content->$text_field_name = str_replace($attachments_tag, '', $content->$text_field_name) . $html;
+ }
+ else
+ {
+ $content->$text_field_name .= $html;
+ }
+ }
+ break;
+ }
+
+ return $content;
+ }
+
+
+ /** Get the parent_id in the component content item editor
+ * (the article or category editor)
+ *
+ * @param string $parent_entity the type of entity for this parent type
+ *
+ * @return the parent ID, null if the content item is being created, and false if there is no match
+ *
+ * @since Attachments 3.2
+ */
+ public function getParentIdInEditor($parent_entity, $view, $layout)
+ {
+ // This should work in the backend for most well-implemented content types--
+ // but not for all frontends, especially not com_content/articles
+ $id = null;
+ if ($view == $parent_entity) {
+ $id = JRequest::getInt('id', $default=null);
+ }
+ else {
+ $id = false;
+ }
+
+ // If we got one, convert it to an int
+ if (is_numeric($id)) {
+ $id = (int)$id;
+ }
+
+ return $id;
+ }
+
+
+ /** See if the attachments list should be displayed in its content description editor
+ *
+ * @param string $parent_entity the type of entity for this parent type
+ * @param string $view the view
+ * @param string $layout the layout on the view
+ *
+ * @return true if the attachments list should be added to the editor
+ */
+ public function showAttachmentsInEditor($parent_entity, $view, $layout)
+ {
+ JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
+ }
+
+
+ /** Insert the attachments list into the entity editor page
+ *
+ * @param int $parent_id the ID for the parent object
+ * @param string $parent_entity the type of entity for this parent type
+ * @param string $attachments the attachments list as a string
+ * @param string $body the editor page text
+ *
+ * @return string the modified editor page text (false for failure)
+ */
+ public function insertAttachmentsListInEditor($parent_id, $parent_entity, $attachments, $body)
+ {
+ // Figure out where to insert the attachments list
+ $reptag = '
get('_name') == 'tinymce') {
+ # Hack because TinyMCE changed the structure
+ $reptag = '
+ * @copyright Copyright (C) 2009-2018 Jonathan M. Cameron, All Rights Reserved
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ * @link http://joomlacode.org/gf/project/attachments/frs/
+ */
+
+// No direct access
+defined('_JEXEC') or die('Restricted access');
+
+/**
+ * Get the singleton plugin manager for attachments
+ *
+ * @return the plugin manager singleton object
+ */
+function &getAttachmentsPluginManager()
+{
+ static $instance;
+
+ if (!is_object($instance))
+ {
+ require_once dirname(__FILE__) . '/attachments_plugin_manager.php';
+ $instance = new AttachmentsPluginManager;
+ }
+
+ return $instance;
+}
+
+
+/** Make sure the plugin class is loaded for derived classes */
+require_once dirname(__FILE__) . '/attachments_plugin.php';
diff --git a/plugins/attachments/attachments_plugin_framework/attachments_plugin_framework.xml b/plugins/attachments/attachments_plugin_framework/attachments_plugin_framework.xml
new file mode 100644
index 00000000..0f6b18bf
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/attachments_plugin_framework.xml
@@ -0,0 +1,23 @@
+
+
+ plg_attachments_plugin_framework
+ 3.2.6
+ March 26, 2018
+ Jonathan M. Cameron
+ jmcameron@jmcameron.net
+ http://joomlacode.org/gf/project/attachments/
+ (C) 2009-2018 Jonathan M. Cameron. All rights reserved.
+ http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ ATTACH_ATTACHMENTS_FOR_COMPONENTS_PLUGIN_FRAMEWORK_DESCRIPTION
+
+ install.php
+
+
+ attachments_plugin_framework.php
+ attachments_plugin.php
+ attachments_plugin_manager.php
+ index.html
+ language
+
+
+
diff --git a/plugins/attachments/attachments_plugin_framework/attachments_plugin_manager.php b/plugins/attachments/attachments_plugin_framework/attachments_plugin_manager.php
new file mode 100644
index 00000000..e8a98b30
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/attachments_plugin_manager.php
@@ -0,0 +1,224 @@
+
+ * @copyright Copyright (C) 2009-2018 Jonathan M. Cameron, All Rights Reserved
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ * @link http://joomlacode.org/gf/project/attachments/frs/
+ */
+
+// No direct access
+defined('_JEXEC') or die('Restricted access');
+
+
+/**
+ * The class for the manager for attachments plugins
+ *
+ * AttachmentsPluginManager manages plugins for Attachments.
+ * It knows how to create handlers for plugins for all
+ * supported extensions.
+ *
+ * @package Attachments
+ * @since 3.0
+ */
+class AttachmentsPluginManager extends JObject
+{
+ /** A list of known parent_type names
+ */
+ private $parent_types = Array();
+
+ /** An array of info about the installed entities.
+ * Each item in the array is an associative array with the following entries:
+ * 'id' - the unique name of entity as stored in the jos_attachments table (all lower case)
+ * 'name' - the translated name of the entity
+ * 'name_plural' - the translated plural name of the entity
+ * 'parent_type' - the parent type for the entity
+ */
+ private $entity_info = Array();
+
+ /** An associative array of attachment plugins
+ */
+ private $plugin = Array();
+
+ /** Flag indicating if the language file haas been loaded
+ */
+ private $language_loaded = false;
+
+ /**
+ * Constructor
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->loadLanguage();
+ }
+
+ /**
+ * See if a particular plugin is installed (avaliable)
+ *
+ * @param string $parent_type the name of the parent extension (eg, com_content)
+ *
+ * @return Boolean true if the plugin is available (false if not)
+ */
+ public function attachmentsPluginInstalled($parent_type)
+ {
+ return in_array($parent_type, $this->parent_types);
+ }
+
+ /**
+ * Check to see if an attachments plugin is enabled
+ *
+ * @param string $parent_type the name of the parent extension (eg, com_content)
+ *
+ * @return true if the attachment is enabled (false if disabled)
+ */
+ public function attachmentsPluginEnabled($parent_type)
+ {
+ // Extract the component name (the part after 'com_')
+ if (strpos($parent_type, 'com_') == 0)
+ {
+ $name = substr($parent_type, 4);
+
+ return JPluginHelper::isEnabled('attachments', "attachments_for_$name");
+ }
+
+ // If the parent type does not conform to the naming convention, assume it is not enabled
+ return false;
+ }
+
+ /**
+ * Add a new parent type
+ *
+ * @param string $new_parent_type the name of the new parent extension (eg, com_content)
+ *
+ * @return nothing
+ */
+ public function addParentType($new_parent_type)
+ {
+ if (in_array($new_parent_type, $this->parent_types))
+ {
+ return;
+ }
+ else
+ {
+ $this->parent_types[] = $new_parent_type;
+ }
+ }
+
+ /**
+ * Return the list of installed parent types
+ *
+ * @return an array of the installed parent types
+ */
+ public function &getInstalledParentTypes()
+ {
+ return $this->parent_types;
+ }
+
+ /**
+ * Return the list of installed parent entities
+ *
+ * @return array of entity info (see var $_entity_info definition above)
+ */
+ public function &getInstalledEntityInfo()
+ {
+ if (count($this->entity_info) == 0)
+ {
+ // Add an option for each entity
+ JPluginHelper::importPlugin('attachments');
+ $apm = getAttachmentsPluginManager();
+
+ // Process all the parent types
+ foreach ($this->parent_types as $parent_type)
+ {
+ $parent = $apm->getAttachmentsPlugin($parent_type);
+ $entities = $parent->getEntities();
+
+ // Process each entity for this parent type
+ foreach ($entities as $entity)
+ {
+ $centity = $parent->getCanonicalEntityId($entity);
+ $this->entity_info[] = array(
+ 'id' => $centity,
+ 'name' => JText::_('ATTACH_' . $centity),
+ 'name_plural' => JText::_('ATTACH_' . $centity . 's'),
+ 'parent_type' => $parent_type
+ );
+ }
+ }
+ }
+
+ return $this->entity_info;
+ }
+
+ /**
+ * Load the langauge for this parent type
+ *
+ * @return true of the language was loaded successfullly
+ */
+ public function loadLanguage()
+ {
+ if ($this->language_loaded)
+ {
+ return true;
+ }
+
+ $lang = JFactory::getLanguage();
+
+ $this->language_loaded = $lang->load('plg_attachments_attachments_plugin_framework', dirname(__FILE__));
+
+ return $this->language_loaded;
+ }
+
+ /**
+ * Get the plugin (attachments parent handler object)
+ *
+ * @param string $parent_type the name of the parent extension (eg, com_content)
+ *
+ * @return the parent handler object
+ */
+ public function getAttachmentsPlugin($parent_type)
+ {
+ // Make sure the parent type is valid
+ if (!in_array($parent_type, $this->parent_types))
+ {
+ $errmsg = JText::sprintf('ATTACH_ERROR_UNKNOWN_PARENT_TYPE_S', $parent_type) . ' (ERR 303)';
+ JError::raiseError(406, $errmsg);
+ }
+
+ // Instantiate the plugin object, if we have not already done it
+ if (!array_key_exists($parent_type, $this->plugin))
+ {
+ $this->installPlugin($parent_type);
+ }
+
+ return $this->plugin[$parent_type];
+ }
+
+ /**
+ * Install the specified plugin
+ *
+ * @param string $parent_type the name of the parent extension (eg, com_content)
+ *
+ * @return true if successful (false if not)
+ */
+ private function installPlugin($parent_type)
+ {
+ // Do nothing if the plugin is already installed
+ if (array_key_exists($parent_type, $this->plugin))
+ {
+ return true;
+ }
+
+ // Install the plugin
+ $dispatcher = JDispatcher::getInstance();
+ $className = 'AttachmentsPlugin_' . $parent_type;
+ $this->plugin[$parent_type] = new $className($dispatcher);
+
+ return is_object($this->plugin[$parent_type]);
+ }
+}
diff --git a/plugins/attachments/attachments_plugin_framework/index.html b/plugins/attachments/attachments_plugin_framework/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/attachments/attachments_plugin_framework/install.php b/plugins/attachments/attachments_plugin_framework/install.php
new file mode 100644
index 00000000..a45e1d48
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/install.php
@@ -0,0 +1,61 @@
+getQuery(true);
+ $query->update('#__extensions')
+ ->set("enabled = 0")
+ ->where('type=' . $db->quote('plugin') . ' AND name=' . $db->quote($plugin_name));
+ $db->setQuery($query);
+ $db->query();
+
+ // NOTE: Do NOT complain if there was an error
+ // (in case any plugin is already uninstalled and this query fails)
+ }
+ }
+
+}
diff --git a/plugins/attachments/attachments_plugin_framework/language/en-GB/en-GB.plg_attachments_attachments_plugin_framework.ini b/plugins/attachments/attachments_plugin_framework/language/en-GB/en-GB.plg_attachments_attachments_plugin_framework.ini
new file mode 100644
index 00000000..4aaf0958
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/language/en-GB/en-GB.plg_attachments_attachments_plugin_framework.ini
@@ -0,0 +1,15 @@
+; en-GB.plg_attachments_plugin_framework.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+ATTACH_ADD_ATTACHMENT_TO="Add Attachment to:"
+ATTACH_ATTACHMENTS_FOR_COMPONENTS_PLUGIN_FRAMEWORK_DESCRIPTION="The Attachments plugin framework plugin provides the plugin framework that enables adding attachments to the content parts of various types of components."
+ATTACH_ERROR_BAD_ENTITY_S_ID="ERROR: Unable to get valid %s ID!"
+ATTACH_ERROR_GETTING_PARENT_S_TITLE_FOR_ID_N="Error getting %s title for ID %d!"
+ATTACH_ERROR_INVALID_ENTITY_S_FOR_PARENT_S="ERROR: Invalid entity '%s' for parent '%s'!"
+ATTACH_ERROR_INVALID_PARENT_S_ID_N="ERROR: Invalid %s parent ID (%d)!"
+ATTACH_NOT_IMPLEMENTED="Not implemented!"
diff --git a/plugins/attachments/attachments_plugin_framework/language/en-GB/en-GB.plg_attachments_attachments_plugin_framework.sys.ini b/plugins/attachments/attachments_plugin_framework/language/en-GB/en-GB.plg_attachments_attachments_plugin_framework.sys.ini
new file mode 100644
index 00000000..06fb4af0
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/language/en-GB/en-GB.plg_attachments_attachments_plugin_framework.sys.ini
@@ -0,0 +1,10 @@
+; en-GB.plg_attachments_plugin_framework.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+ATTACH_ATTACHMENTS_FOR_COMPONENTS_PLUGIN_FRAMEWORK_DESCRIPTION="The Attachments plugin framework plugin provides the plugin framework that enables adding attachments to the content parts of various types of components."
+PLG_ATTACHMENTS_PLUGIN_FRAMEWORK="Attachments - Plugin Framework"
diff --git a/plugins/attachments/attachments_plugin_framework/language/en-GB/index.html b/plugins/attachments/attachments_plugin_framework/language/en-GB/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/language/en-GB/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/attachments/attachments_plugin_framework/language/index.html b/plugins/attachments/attachments_plugin_framework/language/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/language/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/attachments/attachments_plugin_framework/language/it-IT/index.html b/plugins/attachments/attachments_plugin_framework/language/it-IT/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/language/it-IT/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/attachments/attachments_plugin_framework/language/it-IT/it-IT.plg_attachments_attachments_plugin_framework.ini b/plugins/attachments/attachments_plugin_framework/language/it-IT/it-IT.plg_attachments_attachments_plugin_framework.ini
new file mode 100644
index 00000000..92b6e938
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/language/it-IT/it-IT.plg_attachments_attachments_plugin_framework.ini
@@ -0,0 +1,15 @@
+; it-IT.plg_attachments_plugin_framework.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2013 Jonathan M. Cameron, All rights reserved.
+; License GNU GPL 3: http://www.gnu.org/licenses/gpl-3.0.html
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0, 3.0), Lemminkainen (version 1.3.4)
+
+ATTACH_ADD_ATTACHMENT_TO="Aggiungi allegato a:"
+ATTACH_ATTACHMENTS_FOR_COMPONENTS_PLUGIN_FRAMEWORK_DESCRIPTION="Questo plugin fornisce il framework di plugin che permette di aggiungere allegati a segmenti di contenuto di vari tipi di componenti."
+ATTACH_ERROR_BAD_ENTITY_S_ID="ERRORE: Impossibile ottenere ID %s valida!"
+ATTACH_ERROR_GETTING_PARENT_S_TITLE_FOR_ID_N="Errore nell'ottenere %s titolo per ID %d!"
+ATTACH_ERROR_INVALID_ENTITY_S_FOR_PARENT_S="ERRORE: Entità non valida '%s' per genitore '%s'!"
+ATTACH_ERROR_INVALID_PARENT_S_ID_N="ERROR: ID genitore %(i) non valida (%e)!"
+ATTACH_NOT_IMPLEMENTED="Non implementato!"
diff --git a/plugins/attachments/attachments_plugin_framework/language/it-IT/it-IT.plg_attachments_attachments_plugin_framework.sys.ini b/plugins/attachments/attachments_plugin_framework/language/it-IT/it-IT.plg_attachments_attachments_plugin_framework.sys.ini
new file mode 100644
index 00000000..912c36f0
--- /dev/null
+++ b/plugins/attachments/attachments_plugin_framework/language/it-IT/it-IT.plg_attachments_attachments_plugin_framework.sys.ini
@@ -0,0 +1,10 @@
+; it-IT.plg_attachments_plugin_framework.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2013 Jonathan M. Cameron, All rights reserved.
+; License GNU GPL 3: http://www.gnu.org/licenses/gpl-3.0.html
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0, 3.0), Lemminkainen (version 1.3.4)
+
+ATTACH_ATTACHMENTS_FOR_COMPONENTS_PLUGIN_FRAMEWORK_DESCRIPTION="Questo plugin fornisce il framework di plugin che permette di aggiungere allegati a segmenti di contenuto di vari tipi di componenti."
+PLG_ATTACHMENTS_PLUGIN_FRAMEWORK="Allegati - Framework del Plugin"
diff --git a/plugins/content/attachments/attachments.php b/plugins/content/attachments/attachments.php
new file mode 100644
index 00000000..3c6975b6
--- /dev/null
+++ b/plugins/content/attachments/attachments.php
@@ -0,0 +1,424 @@
+
+ * @copyright Copyright (C) 2007-2018 Jonathan M. Cameron, All Rights Reserved
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ * @link http://joomlacode.org/gf/project/attachments/frs/
+ */
+
+defined('_JEXEC') or die('Restricted access');
+
+/** Load the Attachments defines (if available) */
+if (file_exists(JPATH_SITE . '/components/com_attachments/defines.php'))
+{
+ require_once JPATH_SITE . '/components/com_attachments/defines.php';
+ require_once(JPATH_SITE . '/components/com_attachments/helper.php');
+ require_once(JPATH_SITE . '/components/com_attachments/javascript.php');
+}
+else
+{
+ // Exit quietly if the attachments component has been uninstalled or deleted
+ return;
+}
+
+
+/**
+ * Attachments plugin
+ *
+ * @package Attachments
+ * @since 1.3.4
+ */
+class plgContentAttachments extends JPlugin
+{
+ /**
+ * Constructor
+ *
+ * @param object &$subject The object to observe
+ * @param array $config An array that holds the plugin configuration
+ *
+ * @access protected
+ */
+ public function __construct(&$subject, $config)
+ {
+ parent::__construct($subject, $config);
+
+ // Save this page's URL
+ $uri= JFactory::getURI();
+ $return = '&return=' . urlencode(base64_encode(JUri::current() . '?' . $uri->getQuery()));
+ $app = JFactory::getApplication();
+ $app->setUserState('com_attachments.current_url', $return);
+
+ $this->loadLanguage();
+ }
+
+ /**
+ * The content plugin that inserts the attachments list into content items
+ *
+ * @param string The context of the content being passed to the plugin.
+ * @param &object &$row the content object (eg, article) being displayed
+ * @param &object &$params the parameters
+ * @param int $page the 'page' number
+ *
+ * @return true if anything has been inserted into the content object
+ */
+ public function onContentPrepare($context, &$row, &$params, $page = 0)
+ {
+ // Enable the following four diagnostic lines to see if a component uses onContentPrepare
+ // $msg = " onContentPrepare: CONTEXT: $context, OBJ: " . get_class($row) . ", VIEW: " . JRequest::getCmd('view');
+ // if (isset($row->text)) $row->text .= $msg;
+ // if (isset($row->introtext)) $row->introtext .= $msg;
+ // return;
+
+ // Set the parent info from the context
+ if (strpos($context, '.') === false)
+ {
+ // Assume the context is the parent_type
+ $parent_type = $context;
+ $parent_entity = 'default';
+ }
+ else
+ {
+ list ($parent_type, $parent_entity) = explode('.', $context, 2);
+ }
+
+ // This callback handles everything but articles
+ if ( $parent_type == 'com_content' )
+ {
+ if (in_array($parent_entity, Array('featured', 'article'))) {
+ return false;
+ }
+ if ($parent_entity == 'category.title') {
+ // Do not add attachments to categtory titles (Joomla 3 only)
+ return false;
+ }
+ if (($parent_entity == 'category') AND (isset($row->catid))) {
+ // Ignore the callback for articles on category blogs
+ if (version_compare(JVERSION, '3.4.0', 'lt')) {
+ return false;
+ }
+ }
+
+ $parent_entity = 'category';
+
+ // Older versions of Joomla do not deal well with category lists and
+ // it is necessary to use the show_attachments callback to display
+ // category descriptions in those cases.
+ if (version_compare(JVERSION, '2.5.10', 'lt') OR
+ (version_compare(JVERSION, '3.0', 'ge') AND version_compare(JVERSION, '3.1', 'lt'))) {
+ return false;
+ }
+ }
+
+ $view = JRequest::getCmd('view');
+ $layout = JRequest::getCmd('layout');
+
+ if ( ($parent_type == 'mod_custom') AND ($parent_entity == 'content') AND ($view == 'category') )
+ {
+ // Do not add attachments to categtory titles (Joomla 3.4+)
+ return false;
+ }
+
+ // Handle category blog articles specially
+ if (($context == 'com_content.category') AND ($view == 'category') AND ($layout == 'blog')) {
+ if (isset($row->id) and is_numeric($row->id)) {
+ $parent_entity = 'article';
+ }
+ }
+ if (version_compare(JVERSION, '3.7.0'))
+ {
+ # Ignore this for Joomla 3.7.0+ (seems to be new and category attachments are handled ok without it)
+ if ($context == 'com_content.categories')
+ return false;
+ }
+
+ // Get the article/parent handler
+ JPluginHelper::importPlugin('attachments');
+ $apm = getAttachmentsPluginManager();
+ if ( !$apm->attachmentsPluginInstalled($parent_type) ) {
+ // Exit quietly if there is no Attachments plugin to handle this parent_type
+ return false;
+ }
+ $parent = $apm->getAttachmentsPlugin($parent_type);
+
+ // If this attachments plugin is disabled, skip it
+ if ( ! $apm->attachmentsPluginEnabled($parent_type) ) {
+ return false;
+ }
+
+ // Get the parent ID
+ $parent_id = null;
+ if (isset($row->id) and is_numeric($row->id))
+ {
+ // If the $row has 'id', just use it
+ $parent_id = (int)$row->id;
+ }
+ else if ($parent_entity == 'category')
+ {
+ $db = JFactory::getDBO();
+ $description = $row->text;
+ $query = $db->getQuery(true);
+ $query->select('id')->from('#__categories');
+ $query->where('description=' . $db->quote($description));
+ $db->setQuery($query, 0, 1);
+ $result = $db->loadResult();
+ if ($result) {
+ $parent_id = (int)$result;
+ }
+ }
+
+ // Let the attachment pluging try to figure out the id
+ if ( $parent_id === null )
+ {
+ $parent_id = $parent->getParentId($row);
+ }
+
+ if ( $parent_id === null )
+ {
+ return false;
+ }
+
+ // Load the language
+ $lang = JFactory::getLanguage();
+ $lang->load('plg_content_attachments', dirname(__FILE__));
+
+ // Set up the refresh behavior
+ AttachmentsJavascript::setupJavascript();
+
+ // Always include the hide rule (since it may be needed to hide the custom tags)
+ JHtml::stylesheet('com_attachments/attachments_hide.css', Array(), true);
+
+ // Allow remapping of parent ID (eg, for Joomfish)
+ if (jimport('attachments_remapper.remapper'))
+ {
+ $parent_id = AttachmentsRemapper::remapParentID($parent_id, $parent_type, $parent_entity);
+ }
+
+ // Exit if we should not display attachments for this parent
+ if ( $parent->attachmentsHiddenForParent($row, $parent_id, $parent_entity) ) {
+ return false;
+ }
+
+ // Get the component parameters
+ jimport('joomla.application.component.helper');
+ $attachParams = JComponentHelper::getParams('com_attachments');
+
+ // Make sure we should be showing the category attachments
+ $always_show_category_attachments = $attachParams->get('always_show_category_attachments', false);
+ $all_but_article_views = $attachParams->get('hide_except_article_views', false);
+ if ( $all_but_article_views && !$always_show_category_attachments ) {
+ return false;
+ }
+
+ // Add the attachments list
+ $parent->insertAttachmentsList($row, $parent_id, $parent_entity);
+
+ // FOR DEBUGGING
+ // if (isset($row->text)) $row->text .= " [AP text CONTEXT($context) PE($parent_entity) ]";
+ // if (isset($row->introtext)) $row->introtext .= " [AP introtext CONTEXT($context) PE($parent_entity)]";
+
+ return true;
+ }
+
+
+ /**
+ * The content plugin that inserts the attachments list into content items
+ *
+ * @param string $context the context of the content being passed to the plugin.
+ * @param &object &$row the content object (eg, article) being displayed
+ * @param &object &$params the parameters
+ * @param int $page the 'page' number
+ *
+ * @return true if anything has been inserted into the content object
+ */
+ public function onContentBeforeDisplay($context, &$row, &$params, $page = 0)
+ {
+ $view = JRequest::getCmd('view');
+ $layout = JRequest::getCmd('layout');
+ if (($context == 'com_content.category') AND ($view == 'category') AND ($layout == 'blog')) {
+ // Use onContentPrepare for category blog articles for Joomla 3.4+
+ if (version_compare(JVERSION, '3.4', 'ge')) {
+ return false;
+ }
+ }
+
+ // Set the parent info from the context
+ if (strpos($context, '.') === false)
+ {
+ // Assume the context is the parent_type
+ $parent_type = $context;
+ $parent_entity = '';
+ }
+ else
+ {
+ list ($parent_type, $parent_entity) = explode('.', $context, 2);
+ }
+
+ // ??? Do we need to filter to ensure only articles use this callback?
+
+ // Load the language
+ $lang = JFactory::getLanguage();
+ $lang->load('plg_content_attachments', dirname(__FILE__));
+
+ // Add the refresh javascript
+ AttachmentsJavascript::setupJavascript();
+
+ // Always include the hide rule (since it may be needed to hide the custom tags)
+ JHtml::stylesheet('com_attachments/attachments_hide.css', array(), true);
+
+ // Get the article/parent handler
+ JPluginHelper::importPlugin('attachments');
+ $apm = getAttachmentsPluginManager();
+
+ if (!$apm->attachmentsPluginInstalled($parent_type))
+ {
+ // Exit quietly if there is no Attachments plugin to handle this parent_type
+ return false;
+ }
+ $parent = $apm->getAttachmentsPlugin($parent_type);
+
+ // If this attachments plugin is disabled, skip it
+ if (!$apm->attachmentsPluginEnabled($parent_type))
+ {
+ return false;
+ }
+
+ // Figure out the parent entity
+ $parent_entity = $parent->determineParentEntity($row);
+
+ if (!$parent_entity)
+ {
+ return false;
+ }
+
+ // Get the parent ID
+ $parent_id = null;
+ if (isset( $row->id ) && ($row->id > 0)) {
+ $parent_id = (int) $row->id;
+ } else {
+ $parent_id = $parent->getParentId($row);
+ }
+
+ // Exit if there is no parent
+ if ($parent_id === false)
+ {
+ return false;
+ }
+
+ // Allow remapping of parent ID (eg, for Joomfish)
+ if (jimport('attachments_remapper.remapper'))
+ {
+ $parent_id = AttachmentsRemapper::remapParentID($parent_id, $parent_type, $parent_entity);
+ }
+
+ // Exit if we should not display attachments for this parent
+ if ($parent->attachmentsHiddenForParent($row, $parent_id, $parent_entity))
+ {
+ return false;
+ }
+
+ // Add the attachments list
+ $parent->insertAttachmentsList($row, $parent_id, $parent_entity);
+
+ // ??? if (isset($row->text)) $row->text .= " [OCBD text $context]";
+ // ??? if (isset($row->introtext)) $row->introtext .= " [OCBD introtext $context]";
+
+ return;
+ }
+
+
+
+
+ /**
+ * Set the parent_id for all attachments that were added to this
+ * content before it was saved the first time.
+ *
+ * This method is called right after the content is saved.
+ *
+ * @param string The context of the content being passed to the plugin.
+ * @param object $item A JTableContent object
+ * @param bool $isNew If the content is newly created
+ *
+ * @return void
+ */
+ function onContentAfterSave($context, $item, $isNew )
+ {
+ if ( !$isNew ) {
+ // If the item is not new, this step is not needed
+ return true;
+ }
+
+ $ctxinfo = explode('.', $context);
+ $parent_type = $ctxinfo[0];
+ $parent_entity = $ctxinfo[1];
+
+ // Special handling for categories
+ if ( $parent_type == 'com_categories' ) {
+ $parent_type = 'com_content';
+ }
+
+ // Get the attachments associated with this newly created item.
+ // NOTE: We assume that all attachments that have parent_id=null
+ // and are created by the current user are for this item.
+ $user = JFactory::getUser();
+ $user_id = $user->get('id');
+
+ $db = JFactory::getDBO();
+ $query = $db->getQuery(true);
+ $query->select('*')->from('#__attachments');
+ $query->where('created_by=' . (int) $user_id . ' AND parent_id IS NULL');
+ $db->setQuery($query);
+ $attachments = $db->loadObjectList();
+ if ( $db->getErrorNum() ) {
+ $errmsg = $db->stderr() . ' (ERR 200)';
+ JError::raiseError(500, $errmsg);
+ }
+
+ // Exit if there are no new attachments
+ if ( count($attachments) == 0 ) {
+ return true;
+ }
+
+ // Change the attachment to the new content item!
+ JTable::addIncludePath(JPATH_ADMINISTRATOR.'/components/com_attachments/tables');
+ $atrow = JTable::getInstance('Attachment', 'AttachmentsTable');
+
+ foreach ($attachments as $attachment) {
+
+ // Fix for odd issue; on some systems, something is changing the
+ // parent_type in or out of the database
+ if ( ($attachment->parent_type) == 'com_media' AND
+ ($attachment->parent_entity) == 'article' ) {
+ // Override/fix the incorrect parent type
+ $attachment->parent_type = 'com_content';
+ }
+
+ // Change the filename/URL as necessary
+ $error_msg = AttachmentsHelper::switch_parent($attachment, null, $item->id);
+ if ( $error_msg != '' ) {
+ $errmsg = JText::_($error_msg) . ' (ERR 201)';
+ JError::raiseError(500, $errmsg);
+ }
+
+ // Update the parent info
+ $atrow->load($attachment->id);
+ $atrow->parent_id = $item->id;
+ $atrow->parent_type = $parent_type;
+ $atrow->filename_sys = $attachment->filename_sys;
+ $atrow->url = $attachment->url;
+
+ if ( !$atrow->store() ) {
+ $errmsg = $attachment->getError() . ' (ERR 202)';
+ JError::raiseError(500, $errmsg);
+ }
+ }
+
+ return true;
+ }
+
+
+}
diff --git a/plugins/content/attachments/attachments.xml b/plugins/content/attachments/attachments.xml
new file mode 100644
index 00000000..e23d2cf7
--- /dev/null
+++ b/plugins/content/attachments/attachments.xml
@@ -0,0 +1,21 @@
+
+
+ plg_content_attachments
+ 3.2.6
+ March 26, 2018
+ Jonathan M. Cameron
+ jmcameron@jmcameron.net
+ http://joomlacode.org/gf/project/attachments/
+ (C) 2007-2018 Jonathan M. Cameron. All rights reserved.
+ http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ ATTACH_ATTACHMENTS_PLUGIN_DESCRIPTION
+
+ install.php
+
+
+ attachments.php
+ index.html
+ language
+
+
+
diff --git a/plugins/content/attachments/index.html b/plugins/content/attachments/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/content/attachments/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/content/attachments/install.php b/plugins/content/attachments/install.php
new file mode 100644
index 00000000..c79dcc27
--- /dev/null
+++ b/plugins/content/attachments/install.php
@@ -0,0 +1,61 @@
+getQuery(true);
+ $query->update('#__extensions')
+ ->set("enabled = 0")
+ ->where('type=' . $db->quote('plugin') . ' AND name=' . $db->quote($plugin_name));
+ $db->setQuery($query);
+ $db->query();
+
+ // NOTE: Do NOT complain if there was an error
+ // (in case any plugin is already uninstalled and this query fails)
+ }
+ }
+
+}
diff --git a/plugins/content/attachments/language/en-GB/en-GB.plg_content_attachments.ini b/plugins/content/attachments/language/en-GB/en-GB.plg_content_attachments.ini
new file mode 100644
index 00000000..28ae4105
--- /dev/null
+++ b/plugins/content/attachments/language/en-GB/en-GB.plg_content_attachments.ini
@@ -0,0 +1,31 @@
+; en-GB.plg_frontend_attachments.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+; Just for the front end display
+
+ATTACH_ACCESS_THIS_URL_S="Access this URL (%s)"
+ATTACH_ADD_ATTACHMENT="Add attachment"
+ATTACH_ATTACHMENTS="Attachments"
+ATTACH_ATTACHMENTS_PLUGIN_DESCRIPTION="Attachments plugin: Displays a list of the attachments for article (or supported content item),"
+ATTACH_ATTACHMENTS_TITLE="Attachments:"
+ATTACH_CREATED="Created"
+ATTACH_CREATOR="Creator"
+ATTACH_DELETE_THIS_FILE="Delete this file"
+ATTACH_DESCRIPTION="Description"
+ATTACH_DOWNLOADS="Downloads"
+ATTACH_DOWNLOAD_NOUN="Download"
+ATTACH_DOWNLOAD_THIS_FILE_S="Download this file (%s)"
+ATTACH_EXISTING_ATTACHMENTS="Existing Attachments:"
+ATTACH_FILE="File"
+ATTACH_FILE_SIZE="File size"
+ATTACH_FILE_URL="File / URL"
+ATTACH_S_KB="%s kB"
+ATTACH_LAST_MODIFIED="Last modified"
+ATTACH_REALLY_DELETE_ATTACHMENT="Really delete attachment?"
+ATTACH_UPDATE_THIS_FILE="Update this file"
+ATTACH_URL="URL"
diff --git a/plugins/content/attachments/language/en-GB/en-GB.plg_content_attachments.sys.ini b/plugins/content/attachments/language/en-GB/en-GB.plg_content_attachments.sys.ini
new file mode 100644
index 00000000..7c6d641f
--- /dev/null
+++ b/plugins/content/attachments/language/en-GB/en-GB.plg_content_attachments.sys.ini
@@ -0,0 +1,12 @@
+; en-GB.plg_content_attachments.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+; For the plugin manager
+
+ATTACH_ATTACHMENTS_PLUGIN_DESCRIPTION="Attachments plugin: Displays a list of the attachments for article (or supported content item),"
+PLG_CONTENT_ATTACHMENTS="Content - Attachments"
diff --git a/plugins/content/attachments/language/en-GB/index.html b/plugins/content/attachments/language/en-GB/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/content/attachments/language/en-GB/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/content/attachments/language/index.html b/plugins/content/attachments/language/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/content/attachments/language/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/content/attachments/language/it-IT/index.html b/plugins/content/attachments/language/it-IT/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/content/attachments/language/it-IT/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/content/attachments/language/it-IT/it-IT.plg_content_attachments.ini b/plugins/content/attachments/language/it-IT/it-IT.plg_content_attachments.ini
new file mode 100644
index 00000000..b788a582
--- /dev/null
+++ b/plugins/content/attachments/language/it-IT/it-IT.plg_content_attachments.ini
@@ -0,0 +1,30 @@
+; it-IT.plg_frontend_attachments.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2013 Jonathan M. Cameron, All rights reserved.
+; License GNU GPL 3: http://www.gnu.org/licenses/gpl-3.0.html
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0, 3.0), Lemminkainen (version 1.3.4)
+
+; Just for the front end display
+
+ATTACH_ACCESS_THIS_URL_S="Accedi a questo URL (%s)"
+ATTACH_ADD_ATTACHMENT="Aggiungi Allegato"
+ATTACH_ATTACHMENTS="Allegati"
+ATTACH_ATTACHMENTS_PLUGIN_DESCRIPTION="Allegati: questo plugin mostrerà una lista degli allegati disponibili per ciascun articolo (o elemento di contenuto supportato), "
+ATTACH_ATTACHMENTS_TITLE="Allegati:"
+ATTACH_CREATED="Creato"
+ATTACH_CREATOR="Autore"
+ATTACH_DELETE_THIS_FILE="Cancella questo file"
+ATTACH_DESCRIPTION="Descrizione"
+ATTACH_DOWNLOADS="Downloads"
+ATTACH_DOWNLOAD_NOUN="Download"
+ATTACH_DOWNLOAD_THIS_FILE_S="Scarica questo file (%s)"
+ATTACH_EXISTING_ATTACHMENTS="Allegati Esistenti"
+ATTACH_FILE="File"
+ATTACH_FILE_SIZE="Dimensione del File"
+ATTACH_FILE_URL="File / URL"
+ATTACH_LAST_MODIFIED="Modificato il"
+ATTACH_REALLY_DELETE_ATTACHMENT="Confermi la cancellazione dell'allegato?"
+ATTACH_UPDATE_THIS_FILE="Aggiorna questo file"
+ATTACH_URL="URL:"
diff --git a/plugins/content/attachments/language/it-IT/it-IT.plg_content_attachments.sys.ini b/plugins/content/attachments/language/it-IT/it-IT.plg_content_attachments.sys.ini
new file mode 100644
index 00000000..c5754c39
--- /dev/null
+++ b/plugins/content/attachments/language/it-IT/it-IT.plg_content_attachments.sys.ini
@@ -0,0 +1,12 @@
+; it-IT.plg_content_attachments.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2009-2013 Jonathan M. Cameron, All rights reserved.
+; License GNU GPL 3: http://www.gnu.org/licenses/gpl-3.0.html
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0, 3.0), Lemminkainen (version 1.3.4)
+
+; For the plugin manager
+
+ATTACH_ATTACHMENTS_PLUGIN_DESCRIPTION="Plugin allegati: visualizza una lista degli allegati per ogni articolo (o elemento di contenuto supportato),"
+PLG_CONTENT_ATTACHMENTS="Contenuto - Allegati"
diff --git a/plugins/quickicon/attachments/attachments.php b/plugins/quickicon/attachments/attachments.php
new file mode 100644
index 00000000..064630e7
--- /dev/null
+++ b/plugins/quickicon/attachments/attachments.php
@@ -0,0 +1,87 @@
+loadLanguage();
+ }
+
+
+ /**
+ * 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 $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)
+ {
+ // See if we should show the icon
+ if ($context != $this->params->get('context', 'mod_quickicon') ||
+ !JFactory::getUser()->authorise('core.manage', 'com_attachments'))
+ {
+ return;
+ }
+
+ // Add the CSS file
+ JHtml::stylesheet('com_attachments/attachments_quickicon.css', array(), true);
+
+ if (version_compare(JVERSION, '3.0', 'ge'))
+ {
+ $image = 'flag-2';
+ $icon = JUri::root() . '/media/com_attachments/images/attachments_logo48.png';
+ }
+ else
+ {
+ $image = JUri::root() . '/media/com_attachments/images/attachments_logo48.png';
+ $icon = '';
+ }
+
+ // Return the icon info for the quickicon system
+ return
+ array(
+ array(
+ 'link' => 'index.php?option=com_attachments',
+ 'image' => $image,
+ 'icon' => $icon,
+ 'text' => JText::_('PLG_QUICKICON_ATTACHMENTS_ICON'),
+ 'id' => 'plg_quickicon_attachment'));
+ }
+}
diff --git a/plugins/quickicon/attachments/attachments.xml b/plugins/quickicon/attachments/attachments.xml
new file mode 100644
index 00000000..22e200ad
--- /dev/null
+++ b/plugins/quickicon/attachments/attachments.xml
@@ -0,0 +1,29 @@
+
+
+ plg_quickicon_attachments
+ 3.2.6
+ March 26, 2018
+ Jonathan M. Cameron
+ (C) 2007-2018 Jonathan M. Cameron. All rights reserved.
+ http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ jmcameron@jmcameron.net
+ http://joomlacode.org/gf/project/attachments/
+ PLG_QUICKICON_ATTACHMENTS_XML_DESCRIPTION
+
+ attachments.php
+ index.html
+ language
+
+
+
+
+
+
+
diff --git a/plugins/quickicon/attachments/index.html b/plugins/quickicon/attachments/index.html
new file mode 100644
index 00000000..2efb97f3
--- /dev/null
+++ b/plugins/quickicon/attachments/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/quickicon/attachments/language/en-GB/en-GB.plg_quickicon_attachments.ini b/plugins/quickicon/attachments/language/en-GB/en-GB.plg_quickicon_attachments.ini
new file mode 100644
index 00000000..40bc04f0
--- /dev/null
+++ b/plugins/quickicon/attachments/language/en-GB/en-GB.plg_quickicon_attachments.ini
@@ -0,0 +1,13 @@
+; en-GB.plg_quickicon_attachments.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+PLG_QUICKICON_ATTACHMENTS="Quick Icon - Attachments"
+PLG_QUICKICON_ATTACHMENTS_GROUP_DESC="The group of this plugin (this value is compared with the group value used in Quick Icons modules to inject icons)"
+PLG_QUICKICON_ATTACHMENTS_GROUP_LABEL="Group"
+PLG_QUICKICON_ATTACHMENTS_ICON="Attachments Manager"
+PLG_QUICKICON_ATTACHMENTS_XML_DESCRIPTION="Manage the attachments for articles, categories, and other content types."
diff --git a/plugins/quickicon/attachments/language/en-GB/en-GB.plg_quickicon_attachments.sys.ini b/plugins/quickicon/attachments/language/en-GB/en-GB.plg_quickicon_attachments.sys.ini
new file mode 100644
index 00000000..fa0bb665
--- /dev/null
+++ b/plugins/quickicon/attachments/language/en-GB/en-GB.plg_quickicon_attachments.sys.ini
@@ -0,0 +1,10 @@
+; en-GB.plg_quickicon_attachments.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+PLG_QUICKICON_ATTACHMENTS="Quick Icon - Attachments"
+PLG_QUICKICON_ATTACHMENTS_XML_DESCRIPTION="Manage the attachments for articles, categories, and other content types."
diff --git a/plugins/quickicon/attachments/language/en-GB/index.html b/plugins/quickicon/attachments/language/en-GB/index.html
new file mode 100644
index 00000000..2efb97f3
--- /dev/null
+++ b/plugins/quickicon/attachments/language/en-GB/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/quickicon/attachments/language/index.html b/plugins/quickicon/attachments/language/index.html
new file mode 100644
index 00000000..2efb97f3
--- /dev/null
+++ b/plugins/quickicon/attachments/language/index.html
@@ -0,0 +1 @@
+
diff --git a/plugins/quickicon/attachments/language/it-IT/index.html b/plugins/quickicon/attachments/language/it-IT/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/quickicon/attachments/language/it-IT/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/quickicon/attachments/language/it-IT/it-IT.plg_quickicon_attachments.ini b/plugins/quickicon/attachments/language/it-IT/it-IT.plg_quickicon_attachments.ini
new file mode 100644
index 00000000..9c026ae3
--- /dev/null
+++ b/plugins/quickicon/attachments/language/it-IT/it-IT.plg_quickicon_attachments.ini
@@ -0,0 +1,13 @@
+; it-IT.plg_quickicon_attachments.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2013 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0-3.1), Lemminkainen (version 1.3.4)
+
+PLG_QUICKICON_ATTACHMENTS="Icona rapida - Allegati"
+PLG_QUICKICON_ATTACHMENTS_GROUP_DESC="Il gruppo di questo plugin (questo valore è confrontato con il valore del gruppo utilizzato nei moduli Icone rapide per inserire icone"
+PLG_QUICKICON_ATTACHMENTS_GROUP_LABEL="Gruppo"
+PLG_QUICKICON_ATTACHMENTS_ICON="Gestione Allegati"
+PLG_QUICKICON_ATTACHMENTS_XML_DESCRIPTION="Gestisce allegati per articoli, categorie e altri tipi di contenuti"
diff --git a/plugins/quickicon/attachments/language/it-IT/it-IT.plg_quickicon_attachments.sys.ini b/plugins/quickicon/attachments/language/it-IT/it-IT.plg_quickicon_attachments.sys.ini
new file mode 100644
index 00000000..b2e33d1e
--- /dev/null
+++ b/plugins/quickicon/attachments/language/it-IT/it-IT.plg_quickicon_attachments.sys.ini
@@ -0,0 +1,10 @@
+; it-IT.plg_quickicon_attachments.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2013 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0-3.1), Lemminkainen (version 1.3.4)
+
+PLG_QUICKICON_ATTACHMENTS="Icona rapida - Allegati"
+PLG_QUICKICON_ATTACHMENTS_XML_DESCRIPTION="Gestisce allegati per articoli, categorie e altri tipi di contenuti"
diff --git a/plugins/search/attachments/attachments.php b/plugins/search/attachments/attachments.php
new file mode 100644
index 00000000..19816a50
--- /dev/null
+++ b/plugins/search/attachments/attachments.php
@@ -0,0 +1,286 @@
+loadLanguage();
+ }
+
+
+ /**
+ * @return array An array of search areas
+ */
+ public function onContentSearchAreas()
+ {
+ static $areas = array(
+ 'attachments' => 'ATTACH_ATTACHMENTS'
+ );
+ return $areas;
+ }
+
+
+ /**
+ * Attachments Search method
+ *
+ * The sql must return the following fields that are
+ * used in a common display routine: href, title, section, created, text,
+ * browsernav
+ * @param string Target search string
+ * @param string mathcing option, exact|any|all
+ * @param string ordering option, newest|oldest|popular|alpha|category
+ * @param mixed An array if restricted to areas, null if search all
+ */
+ public function onContentSearch($text, $phrase='', $ordering='', $areas=null)
+ {
+ $user = JFactory::getUser();
+
+ // Exit if the search does not include attachments
+ if (is_array($areas)) {
+ if (!array_intersect( $areas, array_keys( $this->onContentSearchAreas()))) {
+ return array();
+ }
+ }
+
+ // Make sure we have something to search for
+ $text = JString::trim( $text );
+ if ($text == '') {
+ return array();
+ }
+
+ // load search limit from plugin params
+ $limit = $this->params->def('search_limit', 50);
+
+ // Get the component parameters
+ jimport('joomla.application.component.helper');
+ $attachParams = JComponentHelper::getParams('com_attachments');
+ $secure = $attachParams->get('secure', false);
+ $user_field_1 = false;
+ if ( JString::strlen($attachParams->get('user_field_1_name', '')) > 0 ) {
+ $user_field_1 = true;
+ $user_field_1_name = $attachParams->get('user_field_1_name');
+ }
+ $user_field_2 = false;
+ if ( JString::strlen($attachParams->get('user_field_2_name', '')) > 0 ) {
+ $user_field_2 = true;
+ $user_field_2_name = $attachParams->get('user_field_2_name');
+ }
+ $user_field_3 = false;
+ if ( JString::strlen($attachParams->get('user_field_3_name', '')) > 0 ) {
+ $user_field_3 = true;
+ $user_field_3_name = $attachParams->get('user_field_3_name');
+ }
+
+ $wheres = array();
+
+ // Create the search query
+ $db = JFactory::getDBO();
+
+ switch ($phrase) {
+
+ case 'exact':
+ $text = $db->quote( '%'.$db->escape( $text, true ).'%', false );
+ $user_fields_sql = '';
+ if ( $user_field_1 )
+ $user_fields_sql .= " OR (LOWER(a.user_field_1) LIKE $text)";
+ if ( $user_field_2 )
+ $user_fields_sql .= " OR (LOWER(a.user_field_2) LIKE $text)";
+ if ( $user_field_3 )
+ $user_fields_sql .= " OR (LOWER(a.user_field_3) LIKE $text)";
+
+ $where = "((LOWER(a.filename) LIKE $text)" .
+ " OR (LOWER(a.display_name) LIKE $text)" .
+ $user_fields_sql .
+ " OR (LOWER(a.description) LIKE $text))";
+ break;
+
+ default:
+ $words = explode( ' ', $text );
+ $wheres = array();
+ foreach ($words as $word) {
+ $word = $db->quote( '%'.$db->escape( $word, true ).'%', false );
+ $wheres2 = array();
+ $wheres2[] = "LOWER(a.filename) LIKE $word";
+ $wheres2[] = "LOWER(a.display_name) LIKE $word";
+ $wheres2[] = "LOWER(a.url) LIKE $word";
+ if ( $user_field_1 )
+ $wheres2[] = "LOWER(a.user_field_1) LIKE $word";
+ if ( $user_field_2 )
+ $wheres2[] = "LOWER(a.user_field_2) LIKE $word";
+ if ( $user_field_3 )
+ $wheres2[] = "LOWER(a.user_field_3) LIKE $word";
+ $wheres2[] = "LOWER(a.description) LIKE $word";
+ $wheres[] = implode( ' OR ', $wheres2 );
+ }
+ $where = '(' . implode( ($phrase == 'all' ? ') AND (' : ') OR ('), $wheres ) . ')';
+ break;
+ }
+
+ // Set up the sorting
+ switch ( $ordering )
+ {
+ case 'oldest':
+ $order = 'a.created ASC';
+ break;
+
+ case 'newest':
+ $order = 'a.created DESC';
+ break;
+
+ case 'alpha':
+ default:
+ $order = 'a.filename DESC';
+ }
+
+ // Load the permissions functions
+ $user = JFactory::getUser();
+ $user_levels = implode(',', array_unique($user->getAuthorisedViewLevels()));
+
+ // Construct and execute the query
+ $query = $db->getQuery(true);
+ $query->select('*')->from('#__attachments AS a');
+ $query->where("( $where ) AND a.state = 1");
+ if ( !$user->authorise('core.admin') ) {
+ $query->where('a.access in ('.$user_levels.')');
+ }
+ $query->order($order);
+ $db->setQuery( $query, 0, $limit );
+ $attachments = $db->loadObjectList();
+
+ $count = count( $attachments );
+
+ // See if we are done
+ $results = Array();
+ if ( $count <= 0 ) {
+ return $results;
+ }
+
+ // Prepare to get parent info
+ JPluginHelper::importPlugin('attachments');
+ $apm = getAttachmentsPluginManager();
+
+ // Add the result data to the results of the search
+ $k = 0;
+ for ( $i = 0; $i < $count; $i++ ) {
+
+ $attachment = $attachments[$i];
+
+ // Get the parent handler
+ $parent_type = $attachment->parent_type;
+ $parent_entity = $attachment->parent_entity;
+ if ( !$apm->attachmentsPluginInstalled($parent_type) ) {
+ // Exit if there is no Attachments plugin to handle this parent_type, ignore it
+ continue;
+ }
+ $parent = $apm->getAttachmentsPlugin($parent_type);
+
+ // Ignore the attachment if the user may not see the parent
+ if ( ! $parent->userMayViewParent($attachment->parent_id, $parent_entity) ) {
+ continue;
+ }
+
+ // Ignore the attachment if the parent is not published
+ if ( ! $parent->isParentPublished($attachment->parent_id, $parent_entity) ) {
+ continue;
+ }
+
+ // Do not add the attachment if the user may not access it
+ if ( !$parent->userMayAccessAttachment($attachment)) {
+ continue;
+ }
+
+ // Add the parent title
+ $attachment->parent_title = $parent->getTitle($attachment->parent_id, $parent_entity);
+
+ // Construct the download URL if necessary
+ if ( $secure && $attachment->uri_type == 'file' ) {
+ $attachment->href =
+ JRoute::_("index.php?option=com_attachments&task=download&id=" . (int)$attachment->id);
+ }
+ else {
+ $attachment->href = $attachment->url;
+ }
+ if ( $attachment->display_name && (JString::strlen($attachment->display_name) > 0) ) {
+ $attachment->title = JString::str_ireplace('·', '.', $attachment->display_name);
+ }
+ else {
+ if ( $attachment->uri_type == 'file' ) {
+ $attachment->title = $attachment->filename;
+ }
+ else {
+ $attachment->title = $attachment->url;
+ }
+ }
+
+ // Set the text to the string containing the search target
+ if ( JString::strlen($attachment->display_name) > 0 ) {
+ $text = $attachment->display_name .
+ " (" . JText::_('ATTACH_FILENAME_COLON') . " " . $attachment->filename . ") ";
+ }
+ else {
+ $text = JText::_('ATTACH_FILENAME_COLON') . " " . $attachment->filename;
+ }
+
+ if ( JString::strlen($attachment->description) > 0 ) {
+ $text .= " | " . JText::_('ATTACH_DESCRIPTION_COLON') . stripslashes($attachment->description);
+ }
+
+ if ( $user_field_1 && (JString::strlen($attachment->user_field_1) > 0) ) {
+ $text .= " | " . $user_field_1_name . ": " . stripslashes($attachment->user_field_1);
+ }
+ if ( $user_field_2 && (JString::strlen($attachment->user_field_2) > 0) ) {
+ $text .= " | " . $user_field_2_name . ": " . stripslashes($attachment->user_field_2);
+ }
+ if ( $user_field_3 && (JString::strlen($attachment->user_field_3) > 0) ) {
+ $text .= " | " . $user_field_3_name . ": " . stripslashes($attachment->user_field_3);
+ }
+ $attachment->text = $text;
+ $attachment->browsernav = 2;
+
+ $parent_entity_name = JText::_('ATTACH_' . $parent_entity);
+ $attachment->parent_entity_name = $parent_entity_name;
+
+ $parent_title = JText::_($parent->getTitle($attachment->parent_id, $parent_entity));
+
+ $attachment->section = JText::sprintf('ATTACH_ATTACHED_TO_PARENT_S_TITLE_S',
+ $parent_entity_name, $parent_title);
+
+ $results[$k] = $attachment;
+ $k++;
+ }
+
+ return $results;
+ }
+
+}
diff --git a/plugins/search/attachments/attachments.xml b/plugins/search/attachments/attachments.xml
new file mode 100644
index 00000000..3121abc2
--- /dev/null
+++ b/plugins/search/attachments/attachments.xml
@@ -0,0 +1,28 @@
+
+
+ plg_search_attachments
+ 3.2.6
+ March 26, 2018
+ Jonathan M. Cameron
+ jmcameron@jmcameron.net
+ http://joomlacode.org/gf/project/attachments/
+ (C) 2007-2018 Jonathan M. Cameron. All rights reserved.
+ http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+ ATTACH_ATTACHMENTS_SEARCH_PLUGIN_DESCRIPTION
+
+
+ attachments.php
+ index.html
+ language
+
+
+
+
+
+
+
+
+
diff --git a/plugins/search/attachments/index.html b/plugins/search/attachments/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/search/attachments/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/search/attachments/language/en-GB/en-GB.plg_search_attachments.ini b/plugins/search/attachments/language/en-GB/en-GB.plg_search_attachments.ini
new file mode 100644
index 00000000..17fc43f0
--- /dev/null
+++ b/plugins/search/attachments/language/en-GB/en-GB.plg_search_attachments.ini
@@ -0,0 +1,15 @@
+; en-GB.plg_search_attachments.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+ATTACH_ATTACHED_TO_PARENT_S_TITLE_S="Attached to %s: %s"
+ATTACH_ATTACHMENTS="Attachments"
+ATTACH_ATTACHMENTS_SEARCH_PLUGIN_DESCRIPTION="The attachments search plugin enables searching all attachment filenames/URLs and descriptions."
+ATTACH_DESCRIPTION_COLON="Description:"
+ATTACH_FILENAME_COLON="Filename:"
+ATTACH_SEARCH_LIMIT="Search limit"
+ATTACH_SEARCH_LIMIT_DESCRIPTION="Number of Search items to return"
diff --git a/plugins/search/attachments/language/en-GB/en-GB.plg_search_attachments.sys.ini b/plugins/search/attachments/language/en-GB/en-GB.plg_search_attachments.sys.ini
new file mode 100644
index 00000000..143d2db5
--- /dev/null
+++ b/plugins/search/attachments/language/en-GB/en-GB.plg_search_attachments.sys.ini
@@ -0,0 +1,10 @@
+; en-GB.plg_search_attachments.sys.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2018 Jonathan M. Cameron, All rights reserved.
+; License http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; English translation
+
+ATTACH_ATTACHMENTS_SEARCH_PLUGIN_DESCRIPTION="The attachments search plugin enables searching all attachment filenames/URLs and descriptions."
+PLG_SEARCH_ATTACHMENTS="Search - Attachments"
diff --git a/plugins/search/attachments/language/en-GB/index.html b/plugins/search/attachments/language/en-GB/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/search/attachments/language/en-GB/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/search/attachments/language/index.html b/plugins/search/attachments/language/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/search/attachments/language/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/search/attachments/language/it-IT/index.html b/plugins/search/attachments/language/it-IT/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/plugins/search/attachments/language/it-IT/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/plugins/search/attachments/language/it-IT/it-IT.plg_search_attachments.ini b/plugins/search/attachments/language/it-IT/it-IT.plg_search_attachments.ini
new file mode 100644
index 00000000..a5e40d54
--- /dev/null
+++ b/plugins/search/attachments/language/it-IT/it-IT.plg_search_attachments.ini
@@ -0,0 +1,15 @@
+; it-IT.plg_search_attachments.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2013 Jonathan M. Cameron, All rights reserved.
+; License GNU GPL 3: http://www.gnu.org/licenses/gpl-3.0.html
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0, 3.0), Lemminkainen (version 1.3.4)
+
+ATTACH_ATTACHED_TO_PARENT_S_TITLE_S="Allegato a %s: %s"
+ATTACH_ATTACHMENTS="Allegati"
+ATTACH_ATTACHMENTS_SEARCH_PLUGIN_DESCRIPTION="Questo plugin consente di effettuare ricerche, comprendenti nomi di file/URL e descrizioni."
+ATTACH_DESCRIPTION_COLON="Descrizione:"
+ATTACH_FILENAME_COLON="Nome del File:"
+ATTACH_SEARCH_LIMIT="Limita la ricerca"
+ATTACH_SEARCH_LIMIT_DESCRIPTION="Numero di elementi da visualizzare"
diff --git a/plugins/search/attachments/language/it-IT/it-IT.plg_search_attachments.sys.ini b/plugins/search/attachments/language/it-IT/it-IT.plg_search_attachments.sys.ini
new file mode 100644
index 00000000..008da60b
--- /dev/null
+++ b/plugins/search/attachments/language/it-IT/it-IT.plg_search_attachments.sys.ini
@@ -0,0 +1,10 @@
+; it-IT.plg_search_attachments.sys.sys.ini
+; Attachments for Joomla! extension
+; Copyright (C) 2007-2013 Jonathan M. Cameron, All rights reserved.
+; License GNU GPL 3: http://www.gnu.org/licenses/gpl-3.0.html
+; Note : All ini files need to be saved as UTF-8 - No BOM
+
+; Italian translation by: Piero Mattirolo (2.0, 3.0), Lemminkainen (version 1.3.4)
+
+ATTACH_ATTACHMENTS_SEARCH_PLUGIN_DESCRIPTION="Questo plugin consente di effettuare ricerche, comprendenti nomi di file/URL e descrizioni."
+PLG_SEARCH_ATTACHMENTS="Cerca - Allegati"