Index: branches/5.2.x/units/link_validation/link_validation_eh.php
===================================================================
--- branches/5.2.x/units/link_validation/link_validation_eh.php	(revision 15939)
+++ branches/5.2.x/units/link_validation/link_validation_eh.php	(revision 15940)
@@ -1,571 +1,571 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Link
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class LinkValidationEventHandler extends kDBEventHandler {
 
 		/**
 		 * Allows to override standard permission mapping
 		 *
 		 * @return void
 		 * @access protected
 		 * @see kEventHandler::$permMapping
 		 */
 		protected function mapPermissions()
 		{
 			parent::mapPermissions();
 
 			$permissions = Array (
 				'OnResetValidationStatus' => Array ('self' => 'advanced:reset',),
 				'OnRestartValidation' => Array ('self' => 'advanced:restart',),
 				'OnContinueValidation' => Array ('self' => 'advanced:continue',),
 				'OnValidateSelected' => Array ('self' => 'advanced:validate',),
 				'OnValidateProgress' => Array ('self' => 'advanced:validate|advanced:continue|advanced:restart|advanced:reset',),
 				'OnCancelValidation' => Array ('self' => 'advanced:validate|advanced:continue|advanced:restart|advanced:reset',),
 				'OnCronValidation' => Array ('self' => 'advanced:validate|advanced:continue|advanced:restart|advanced:reset',),
 			);
 
 			$this->permMapping = array_merge($this->permMapping, $permissions);
 		}
 
 		/**
 		 * Define alternative event processing method names
 		 *
 		 * @return void
 		 * @see kEventHandler::$eventMethods
 		 * @access protected
 		 */
 		protected function mapEvents()
 		{
 			parent::mapEvents();
 
 			$events_map = Array (
 				'OnApproveLinks' => 'iterateItems',
 				'OnDeclineLinks' => 'iterateItems',
 			);
 
 			$this->eventMethods = array_merge($this->eventMethods, $events_map);
 		}
 
 		/**
 		 * Checks user permission to execute given $event
 		 *
 		 * @param kEvent $event
 		 * @return bool
 		 * @access public
 		 */
 		public function CheckPermission(kEvent $event)
 		{
 			$check_events = Array ('OnApproveLinks', 'OnDeclineLinks', 'OnDeleteLinks');
 
 			if ( in_array($event->Name, $check_events) ) {
 				$ids = $this->_getSelectedIds($event);
 
 				$perm_value = true;
 				if ( $ids ) {
 					$perm_helper = $this->Application->recallObject('PermissionsHelper');
 					/* @var $perm_helper kPermissionsHelper */
 
 					$items = $perm_helper->GetCategoryItemData('l', $ids);
 					$check_method = $event->Name == 'OnDeleteLinks' ? 'DeleteCheckPermission' : 'ModifyCheckPermission';
 					foreach ($items as $item_id => $item_data) {
 						if ( $perm_helper->$check_method($item_data['CreatedById'], $item_data['CategoryId'], 'l') == 0 ) {
 							// one of items selected has no permission
 							$perm_value = false;
 							break;
 						}
 					}
 
 					if ( !$perm_value ) {
 						$event->status = kEvent::erPERM_FAIL;
 					}
 				}
 
 				return $perm_value;
 			}
 
 			return parent::CheckPermission($event);
 		}
 
 		/**
 		 * Adds calculates fields for category name
 		 *
 		 * @param kDBItem|kDBList $object
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function prepareObject(&$object, kEvent $event)
 		{
 			parent::prepareObject($object, $event);
 
 			$object->addCalculatedField('CachedNavbar', 'c.l' . $this->Application->GetVar('m_lang') . '_CachedNavbar');
 		}
 
 		/**
 		 * Allows to show only invalid links
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 * @see kDBEventHandler::OnListBuild()
 		 */
 		protected function SetCustomQuery(kEvent $event)
 		{
 			parent::SetCustomQuery($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBList */
 
 			$object->addFilter('primary_category_filter', 'ci.PrimaryCat = 1');
 
 			if ( $event->Special == 'invalid' ) {
 				$object->addFilter('status_filter', '%1$s.ValidationStatus = ' . LINK_VALIDATION_INVALID);
 			}
 		}
 
 		/**
 		 * Restarts link validation process
 		 *
 		 * @param kEvent $event
 		 */
 		function OnRestartValidation($event)
 		{
 			$this->_resetValidation($event);
 
 			$this->OnContinueValidation($event);
 		}
 
 		/**
 		 * Restarts link validation process
 		 *
 		 * @param kEvent $event
 		 */
 		function _resetValidation($event)
 		{
 			// 1. delete previous validation results
 			$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
 					FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName');
 			$ids = $this->Conn->GetCol($sql);
 
 			if ($ids) {
 				$temp_handler = $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
 				/* @var $temp_handler kTempTablesHandler */
 
 				$temp_handler->DeleteItems($event->Prefix, $event->Special, $ids);
 			}
 		}
 
 		/**
 		 * Validates only selected links
 		 *
 		 * @param kEvent $event
 		 */
 		function OnValidateSelected($event)
 		{
 			$link_ids = $this->_getSelectedIds($event);
 			if (!$link_ids) {
 				return ;
 			}
 
 			$validation_data = Array (
 				'processed' => 0,
 				'total' => count($link_ids),
 				'items' => $link_ids,
 			);
 			$this->Application->StoreVar($event->Prefix . '_status', serialize($validation_data));
 
 			$event->redirect = $this->Application->GetVar('progress_template');
 		}
 
 		/**
 		 * Validates only links, that were not previously validated
 		 *
 		 * @param kEvent $event
 		 */
 		function OnContinueValidation($event)
 		{
 			$have_data = $this->_prepareValidation($event);
 			if ($have_data) {
 				$event->redirect = $this->Application->GetVar('progress_template');
 			}
 		}
 
 		/**
 		 * Performs validation
 		 *
 		 * @param kEvent $event
 		 * @param bool $from_ajax
 		 */
 		function _validate($event, $from_ajax = true)
 		{
 			$validation_data = unserialize( $this->Application->RecallVar($event->Prefix . '_status') );
 
 			$i = 0;
 			$link_ids = $validation_data['items'];
 			$per_page = count($link_ids) >= LINK_VALIDATION_PER_PAGE ? LINK_VALIDATION_PER_PAGE : count($link_ids);
 
 			while ($i < $per_page) {
 				$this->_validateLink($link_ids[$i]);
 				$i++;
 			}
 
 			// remove processed links from array
 			array_splice($link_ids, 0, LINK_VALIDATION_PER_PAGE);
 
 			// store validation progress
 			$validation_data['processed'] += $i;
 			$validation_data['items'] = $link_ids;
 
 			if ($validation_data['processed'] >= $validation_data['total']) {
 				// finished
 				$this->Application->emailAdmin('LINK.VALIDATION.RESULTS');
 
 				$this->Application->RemoveVar($event->Prefix . '_status');
 				return true;
 			}
 
 			// show progress, proceed to next step
 			$this->Application->StoreVar($event->Prefix . '_status', serialize($validation_data));
 
 			if ($from_ajax) {
 				echo $validation_data['processed'] / $validation_data['total'] * 100;
 				$event->status = kEvent::erSTOP;
 			}
 
 			return false;
 		}
 
 		/**
 		 * Performs validation of links (called from AjaxProgressBar)
 		 *
 		 * @param kEvent $event
 		 */
 		function OnValidateProgress($event)
 		{
 			$done = $this->_validate($event, true);
 
 			if ($done) {
 				$this->Application->Redirect( $this->Application->GetVar('finish_template') );
 			}
 		}
 
 		/**
 		 * Returns categories, that are located inside recycle bin category
 		 *
 		 * @return Array
 		 */
 		function _getRecycleBinCategories()
 		{
 			$recycle_bin = $this->Application->ConfigValue('RecycleBinFolder');
 			if (!is_numeric($recycle_bin)) {
 				return Array ();
 			}
 
 			$recycle_categories = $this->Application->RecallVar('recycle_categories');
 			if ($recycle_categories === false) {
 				$tree_indexes = $this->Application->getTreeIndex($recycle_bin);
 
 				$sql = 'SELECT ' . $this->Application->getUnitOption('c', 'IDField') . '
 						FROM ' . $this->Application->getUnitOption('c', 'TableName') . '
 						WHERE TreeLeft BETWEEN ' . $tree_indexes['TreeLeft'] . ' AND ' . $tree_indexes['TreeRight'];
 				$recycle_categories = serialize( $this->Conn->GetCol($sql) );
 
 				// store recycle bin categories in session to prevent query below happening on each link validation step
 				$this->Application->StoreVar('recycle_categories', $recycle_categories);
 			}
 
 			return unserialize($recycle_categories);
 
 		}
 
 		/**
 		 * Checks, that link is located in one of RecycleBin subcategories
 		 *
 		 * @param unknown_type $resource_id
 		 * @return unknown
 		 */
 		function _inRecycleBin($resource_id)
 		{
 			static $recycle_bin = null;
 
 			if (!isset($recycle_bin)) {
 				$recycle_bin = $this->_getRecycleBinCategories();
 			}
 
 			if (!$recycle_bin) {
 				// Recycle Bin not used in system -> link is 100% not there
 				return false;
 			}
 
 			$sql = 'SELECT CategoryId
 					FROM ' . $this->Application->getUnitOption('l-ci', 'TableName') . '
 					WHERE ItemResourceId = ' . $resource_id . ' AND PrimaryCat = 1';
 
 			return in_array( $this->Conn->GetOne($sql), $recycle_bin);
 		}
 
 		function _validateLink($link_id)
 		{
 			$curl_helper = $this->Application->recallObject('CurlHelper');
 			/* @var $curl_helper kCurlHelper */
 
 			$sql = 'SELECT Url, ResourceId
 					FROM ' . $this->Application->getUnitOption('l', 'TableName') . '
 					WHERE ' . $this->Application->getUnitOption('l', 'IDField') . ' = ' . $link_id;
 			$link_data = $this->Conn->GetRow($sql);
 
 			if (!preg_match('/^(http|https):\/\/(.*)/U', $link_data['Url']) || $this->_inRecycleBin($link_data['ResourceId'])) {
 				return ;
 			}
 
 			$curl_helper->timeout = LINK_VALIDATION_TIMEOUT;
 
 			$result = $curl_helper->Send($link_data['Url']);
 			if ($result === false || $curl_helper->lastErrorMsg != '') {
-				$curl_helper->lastErrorCode = 500;
+				$curl_helper->lastHTTPCode = 500;
 			}
 
 			$link_validation = $this->Application->recallObject($this->Prefix . '.-item', null, Array ('skip_autoload' => true));
 			/* @var $link_validation kDBItem */
 
 			$link_validation->Load($link_id, 'LinkId');
 
 			$now = adodb_mktime();
 
 			$fields_hash = Array (
 				'LinkId' => $link_id,
 				'ValidationTime_date' => $now,
 				'ValidationTime_time' => $now,
 				'ValidationCode' => $curl_helper->lastHTTPCode,
 				'ValidationStatus' => $curl_helper->lastHTTPCode < 400 ? LINK_VALIDATION_VALID : LINK_VALIDATION_INVALID,
 			);
 			$link_validation->SetDBFieldsFromHash($fields_hash);
 
 			return $link_validation->isLoaded() ? $link_validation->Update() : $link_validation->Create();
 		}
 
 		/**
 		 * Cancels validation (from validation progress bar)
 		 *
 		 * @param kEvent $event
 		 */
 		function OnCancelValidation($event)
 		{
 			$this->Application->RemoveVar($event->Prefix . '_status');
 		}
 
 		/**
 		 * Resets validation status for selected
 		 *
 		 * @param kEvent $event
 		 */
 		function OnResetValidationStatus($event)
 		{
 			$ids = $this->_getSelectedIds($event, true);
 			if (!$ids) {
 				return ;
 			}
 
 			$temp_handler = $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
 			/* @var $temp_handler kTempTablesHandler */
 
 			$temp_handler->DeleteItems($event->Prefix, $event->Special, $ids);
 		}
 
 		/**
 		 * Returns ids, that user has checked in grid
 		 *
 		 * @param kEvent $event
 		 * @param bool $transform convert link ids to link validation ids
 		 * @return Array
 		 */
 		function _getSelectedIds($event, $transform = false)
 		{
 			$ids = Array();
 
 			$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
 			if ($items_info) {
 				foreach ($items_info as $id => $field_values) {
 					if ( getArrayValue($field_values, 'ForeignLinkId') ) {
 						// we are not gathering ids by unit idfield here!
 						array_push($ids, $id);
 					}
 				}
 			}
 
 			if ($transform && $ids) {
 				$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
 						FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 						WHERE LinkId IN (' . implode(',', $ids) . ')';
 				$ids = $this->Conn->GetCol($sql);
 			}
 
 			return $ids;
 		}
 
 		/**
 		 * Approves/declines selected links
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function iterateItems(kEvent $event)
 		{
 			if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
 				$event->status = kEvent::erFAIL;
 				return;
 			}
 
 			$ids = $this->_getSelectedIds($event);
 			if ( !$ids ) {
 				return;
 			}
 
 			$object = $this->Application->recallObject('l.-item', null, Array ('skip_autoload' => true));
 			/* @var $object kCatDBItem */
 
 			foreach ($ids as $id) {
 				$ret = true;
 				$object->Load($id);
 
 				switch ( $event->Name ) {
 					case 'OnApproveLinks':
 						$ret = $object->ApproveChanges();
 						break;
 
 					case 'OnDeclineLinks':
 						$ret = $object->DeclineChanges();
 						break;
 				}
 
 				if ( !$ret ) {
 					$event->status = kEvent::erFAIL;
 					$event->redirect = false;
 					break;
 				}
 			}
 		}
 
 		/**
 		 * Deletes selected links
 		 *
 		 * @param kEvent $event
 		 */
 		function OnDeleteLinks($event)
 		{
 			if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
 				$event->status = kEvent::erFAIL;
 				return;
 			}
 
 			$ids = $this->_getSelectedIds($event);
 			if (!$ids) {
 				return ;
 			}
 
 			$temp_handler = $this->Application->recallObject('l_TempHandler', 'kTempTablesHandler');
 			/* @var $temp_handler kTempTablesHandler */
 
 			$temp_handler->DeleteItems('l', '', $ids);
 		}
 
 		/**
 		 * [HOOK] Allows to edit links, used in selected link validation records
 		 *
 		 * @param kEvent $event
 		 */
 		function OnPrepareLinkEditing($event)
 		{
 			// hook to OnAfterConfigRead instead of OnEdit, because fake ids should be available in CheckPermission
 			if ($this->Application->GetVar('l_event') != 'OnEdit') {
 				return ;
 			}
 
 			$ids = $this->_getSelectedIds($event);
 			$id_field = $this->Application->getUnitOption('l', 'IDField');
 
 			$items_info = Array ();
 			foreach ($ids as $id) {
 				$items_info[$id][$id_field] = 'on';
 			}
 
 			$this->Application->SetVar('l', $items_info);
 		}
 
 		/**
 		 * Gets all links, that are not yet validated and prepare data
 		 *
 		 * @param kEvent $event
 		 *
 		 * @return bool
 		 */
 		function _prepareValidation($event)
 		{
 			// 2. get ids of all links and put them into validation queue
 			$id_field = $this->Application->getUnitOption('l', 'IDField');
 			$sql = 'SELECT ' . $id_field . '
 					FROM ' . $this->Application->getUnitOption('l', 'TableName') . '
 					WHERE LinkId NOT IN (SELECT LinkId FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . ')';
 			$link_ids = $this->Conn->GetCol($sql);
 
 			if ($link_ids) {
 				$validation_data = Array (
 					'processed' => 0,
 					'total' => count($link_ids),
 					'items' => $link_ids,
 				);
 				$this->Application->StoreVar($event->Prefix . '_status', serialize($validation_data)); // 4K links will be 78KB serialized
 				return true;
 			}
 
 			return false;
 		}
 
 		/**
 		 * [SCHEDULED TASK] Performs link validation through cron
 		 *
 		 * @param kEvent $event
 		 */
 		function OnCronValidation($event)
 		{
 			$this->_resetValidation($event); // remove this for continuing to non validated before links
 
 			$have_data = $this->_prepareValidation($event);
 			if ($have_data) {
 				do {
 					$done = $this->_validate($event, false);
 				} while (!$done);
 			}
 		}
 
 		/**
 		 * Makes calculated fields to go to multilingual link fields
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnAfterConfigRead(kEvent $event)
 		{
 			parent::OnAfterConfigRead($event);
 
 			$calculated_fields = $this->Application->getUnitOption($event->Prefix, 'CalculatedFields');
 			$calculated_fields['']['LinkName'] = 'l.l' . $this->Application->GetVar('m_lang') . '_Name';
 			$this->Application->setUnitOption($event->Prefix, 'CalculatedFields', $calculated_fields);
 		}
 
 	}
\ No newline at end of file