[FEATURE] Move class "tx_scheduler_Module" from "mod1/index.php" for unit test
authorAndy Grunwald <andreas.grunwald@wmdb.de>
Tue, 12 Apr 2011 20:06:39 +0000 (22:06 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sat, 16 Apr 2011 15:39:44 +0000 (17:39 +0200)
This change makes it possible to write unit tests for "tx_scheduler_module".

Change-Id: I85b977687c24966aadba11248a58ee081b8bef67
Resolves: #25925
Releases: 4.6
Reviewed-on: http://review.typo3.org/1588
Reviewed-by: Christian Kuhn
Tested-by: Christian Kuhn
typo3/sysext/scheduler/class.tx_scheduler_module.php [new file with mode: 0644]
typo3/sysext/scheduler/ext_autoload.php
typo3/sysext/scheduler/mod1/index.php

diff --git a/typo3/sysext/scheduler/class.tx_scheduler_module.php b/typo3/sysext/scheduler/class.tx_scheduler_module.php
new file mode 100644 (file)
index 0000000..b2e138b
--- /dev/null
@@ -0,0 +1,1607 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009-2011 François Suter <francois@typo3.org>
+*  (c) 2005 Christian Jul Jensen <julle@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Module 'TYPO3 Scheduler administration module' for the 'scheduler' extension.
+ *
+ * @author             François Suter <francois@typo3.org>
+ * @author             Christian Jul Jensen <julle@typo3.org>
+ * @author             Ingo Renner <ingo@typo3.org>
+ * @package            TYPO3
+ * @subpackage tx_scheduler
+ */
+class tx_scheduler_Module extends t3lib_SCbase {
+
+       /**
+        * Back path to typo3 main dir
+        *
+        * @var string          $backPath
+        */
+       public $backPath;
+
+       /**
+        * Array containing submitted data when editing or adding a task
+        *
+        * @var array           $submittedData
+        */
+       protected $submittedData = array();
+
+       /**
+        * Array containing all messages issued by the application logic
+        * Contains the error's severity and the message itself
+        *
+        * @var array   $messages
+        */
+       protected $messages = array();
+
+       /**
+        * @var string  Key of the CSH file
+        */
+       protected $cshKey;
+
+       /**
+        *
+        * @var tx_scheduler    Local scheduler instance
+        */
+       protected $scheduler;
+
+       /**
+        * Constructor
+        *
+        * @return      void
+        */
+       public function __construct() {
+               $this->backPath = $GLOBALS['BACK_PATH'];
+                       // Set key for CSH
+               $this->cshKey = '_MOD_' . $GLOBALS['MCONF']['name'];
+       }
+
+       /**
+        * Initializes the backend module
+        *
+        * @return      void
+        */
+       public function init() {
+               parent::init();
+
+                       // Initialize document
+               $this->doc = t3lib_div::makeInstance('template');
+               $this->doc->setModuleTemplate(t3lib_extMgm::extPath('scheduler') . 'mod1/mod_template.html');
+               $this->doc->getPageRenderer()->addCssFile(t3lib_extMgm::extRelPath('scheduler') . 'res/tx_scheduler_be.css');
+               $this->doc->backPath = $this->backPath;
+               $this->doc->bodyTagId = 'typo3-mod-php';
+               $this->doc->bodyTagAdditions = 'class="tx_scheduler_mod1"';
+
+                       // Create scheduler instance
+               $this->scheduler = t3lib_div::makeInstance('tx_scheduler');
+       }
+
+       /**
+        * Adds items to the ->MOD_MENU array. Used for the function menu selector.
+        *
+        * @return      void
+        */
+       public function menuConfig() {
+               $this->MOD_MENU = array(
+                       'function' => array(
+                               'scheduler' => $GLOBALS['LANG']->getLL('function.scheduler'),
+                               'check'     => $GLOBALS['LANG']->getLL('function.check'),
+                               'info'      => $GLOBALS['LANG']->getLL('function.info'),
+                       )
+               );
+
+               parent::menuConfig();
+       }
+
+       /**
+        * Main function of the module. Write the content to $this->content
+        *
+        * @return      void
+        */
+       public function main() {
+                       // Access check!
+                       // The page will show only if user has admin rights
+               if ($GLOBALS['BE_USER']->user['admin']) {
+
+                               // Set the form
+                       $this->doc->form = '<form name="tx_scheduler_form" id="tx_scheduler_form" method="post" action="">';
+
+                               // JavaScript for main function menu
+                       $this->doc->JScode = '
+                               <script language="javascript" type="text/javascript">
+                                       script_ended = 0;
+                                       function jumpToUrl(URL) {
+                                               document.location = URL;
+                                       }
+                               </script>
+                       ';
+
+                               // Prepare main content
+                       $this->content  = $this->doc->header(
+                               $GLOBALS['LANG']->getLL('function.' . $this->MOD_SETTINGS['function'])
+                       );
+                       $this->content .= $this->doc->spacer(5);
+                       $this->content .= $this->getModuleContent();
+               } else {
+                               // If no access, only display the module's title
+                       $this->content  = $this->doc->header($GLOBALS['LANG']->getLL('title'));
+                       $this->content .= $this->doc->spacer(5);
+               }
+
+                       // Place content inside template
+
+               $content = $this->doc->moduleBody(
+                       array(),
+                       $this->getDocHeaderButtons(),
+                       $this->getTemplateMarkers()
+               );
+
+                       // Renders the module page
+               $this->content = $this->doc->render(
+                       $GLOBALS['LANG']->getLL('title'),
+                       $content
+               );
+       }
+
+       /**
+        * Generate the module's content
+        *
+        * @return      string  HTML of the module's main content
+        */
+       protected function getModuleContent() {
+               $content = '';
+               $sectionTitle = '';
+
+                       // Get submitted data
+               $this->submittedData = t3lib_div::_GPmerged('tx_scheduler');
+
+                       // If a save command was submitted, handle saving now
+               if ($this->CMD == 'save') {
+                       $previousCMD = t3lib_div::_GP('previousCMD');
+                               // First check the submitted data
+                       $result = $this->preprocessData();
+
+                               // If result is ok, proceed with saving
+                       if ($result) {
+                               $this->saveTask();
+                                       // Unset command, so that default screen gets displayed
+                               unset($this->CMD);
+
+                               // Errors occurred
+                               // Go back to previous step
+                       } else {
+                               $this->CMD = $previousCMD;
+                       }
+               }
+
+                       // Handle chosen action
+               switch((string)$this->MOD_SETTINGS['function']) {
+                       case 'scheduler':
+                                       // Scheduler's main screen
+                               $content .= $this->executeTasks();
+
+                                       // Execute chosen action
+                               switch ($this->CMD) {
+                                       case 'add':
+                                       case 'edit':
+                                               try {
+                                                               // Try adding or editing
+                                                       $content .= $this->editTask();
+                                                       $sectionTitle = $GLOBALS['LANG']->getLL('action.' . $this->CMD);
+                                               } catch (Exception $e) {
+                                                               // An exception may happen when the task to
+                                                               // edit could not be found. In this case revert
+                                                               // to displaying the list of tasks
+                                                               // It can also happend when attempting to edit a running task
+                                                       $content .= $this->listTasks();
+                                               }
+                                               break;
+                                       case 'delete':
+                                               $this->deleteTask();
+                                               $content .= $this->listTasks();
+                                               break;
+                                       case 'stop':
+                                               $this->stopTask();
+                                               $content .= $this->listTasks();
+                                               break;
+                                       case 'list':
+                                       default:
+                                               $content .= $this->listTasks();
+                                               break;
+                               }
+                               break;
+                       case 'check':
+                                       // Setup check screen
+                                       // TODO: move check to the report module
+                               $content .= $this->displayCheckScreen();
+                               break;
+                       case 'info':
+                                       // Information screen
+                               $content .= $this->displayInfoScreen();
+                               break;
+               }
+
+                       // Wrap the content in a section
+               return $this->doc->section($sectionTitle, '<div class="tx_scheduler_mod1">' . $content . '</div>', 0, 1);
+       }
+
+       /**
+        * This method actually prints out the module's HTML content
+        *
+        * @return      void
+        */
+       public function render() {
+               echo $this->content;
+       }
+
+       /**
+        * This method checks the status of the '_cli_scheduler' user
+        * It will differentiate between a non-existing user and an existing,
+        * but disabled user (as per enable fields)
+        *
+        * @return      integer         -1      if user doesn't exist
+        *                                               0      if user exists, but is disabled
+        *                                               1      if user exists and is not disabled
+        */
+       protected function checkSchedulerUser() {
+               $schedulerUserStatus = -1;
+                       // Assemble base WHERE clause
+               $where = 'username = \'_cli_scheduler\' AND admin = 0' . t3lib_BEfunc::deleteClause('be_users');
+                       // Check if user exists at all
+               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                       '1',
+                       'be_users',
+                       $where
+               );
+               if ($GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                       $schedulerUserStatus = 0;
+                               // Check if user exists and is enabled
+                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                               '1',
+                               'be_users',
+                               $where . t3lib_BEfunc::BEenableFields('be_users')
+                       );
+                       if ($GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                               $schedulerUserStatus = 1;
+                       }
+               }
+               $GLOBALS['TYPO3_DB']->sql_free_result($res);
+
+               return $schedulerUserStatus;
+       }
+
+       /**
+        * This method creates the "cli_scheduler" BE user if it doesn't exist
+        *
+        * @return      void
+        */
+       protected function createSchedulerUser() {
+                       // Check _cli_scheduler user status
+               $checkUser = $this->checkSchedulerUser();
+                       // Prepare default message
+               $message = $GLOBALS['LANG']->getLL('msg.userExists');
+               $severity = t3lib_FlashMessage::WARNING;
+                       // If the user does not exist, try creating it
+               if ($checkUser == -1) {
+                               // Prepare necessary data for _cli_scheduler user creation
+                       $password = md5(uniqid('scheduler', true));
+                       $data = array('be_users' => array('NEW' => array('username' => '_cli_scheduler', 'password' => $password, 'pid' => 0)));
+                               /**
+                                * Create an instance of TCEmain and execute user creation
+                                *
+                                * @var t3lib_TCEmain
+                                */
+                       $tcemain = t3lib_div::makeInstance('t3lib_TCEmain');
+                       $tcemain->stripslashes_values = 0;
+                       $tcemain->start($data, array());
+                       $tcemain->process_datamap();
+                               // Check if a new uid was indeed generated (i.e. a new record was created)
+                               // (counting TCEmain errors doesn't work as some failures don't report errors)
+                       $numberOfNewIDs = count($tcemain->substNEWwithIDs);
+                       if ($numberOfNewIDs == 1) {
+                               $message = $GLOBALS['LANG']->getLL('msg.userCreated');
+                               $severity = t3lib_FlashMessage::OK;
+                       } else {
+                               $message = $GLOBALS['LANG']->getLL('msg.userNotCreated');
+                               $severity = t3lib_FlashMessage::ERROR;
+                       }
+               }
+               $this->addMessage($message, $severity);
+       }
+
+       /**
+        * This method displays the result of a number of checks
+        * on whether the Scheduler is ready to run or running properly
+        *
+        * @return      string  further information
+        */
+       protected function displayCheckScreen() {
+               $message = '';
+               $severity = t3lib_FlashMessage::OK;
+
+                       // First, check if cli_sceduler user creation was requested
+               if ($this->CMD == 'user') {
+                       $this->createSchedulerUser();
+               }
+
+                       // Start generating the content
+               $content = $GLOBALS['LANG']->getLL('msg.schedulerSetupCheck');
+
+                       // Display information about last automated run, as stored in the system registry
+                       /**
+                        * @var t3lib_Registry
+                        */
+               $registry = t3lib_div::makeInstance('t3lib_Registry');
+               $lastRun = $registry->get('tx_scheduler', 'lastRun');
+               if (!is_array($lastRun)) {
+                       $message = $GLOBALS['LANG']->getLL('msg.noLastRun');
+                       $severity = t3lib_FlashMessage::WARNING;
+               } else {
+                       if (empty($lastRun['end']) || empty($lastRun['start']) || empty($lastRun['type'])) {
+                               $message = $GLOBALS['LANG']->getLL('msg.incompleteLastRun');
+                               $severity = t3lib_FlashMessage::WARNING;
+                       } else {
+                               $startDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $lastRun['start']);
+                               $startTime = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $lastRun['start']);
+                               $endDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $lastRun['end']);
+                               $endTime = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $lastRun['end']);
+                               $label = 'automatically';
+                               if ($lastRun['type'] == 'manual') {
+                                       $label = 'manually';
+                               }
+                               $type = $GLOBALS['LANG']->getLL('label.' . $label);
+                               $message = sprintf($GLOBALS['LANG']->getLL('msg.lastRun'), $type, $startDate, $startTime, $endDate, $endTime);
+                               $severity = t3lib_FlashMessage::INFO;
+                       }
+               }
+               $flashMessage = t3lib_div::makeInstance(
+                       't3lib_FlashMessage',
+                       $message,
+                       '',
+                       $severity
+               );
+               $content .= '<div class="info-block">';
+               $content .= '<h3>' . $GLOBALS['LANG']->getLL('hdg.lastRun') . '</h3>';
+               $content .= $flashMessage->render();
+               $content .= '</div>';
+
+                       // Check CLI user
+               $content .= '<div class="info-block">';
+               $content .= '<h3>' . $GLOBALS['LANG']->getLL('hdg.schedulerUser') . '</h3>';
+               $content .= '<p>' . $GLOBALS['LANG']->getLL('msg.schedulerUser') . '</p>';
+
+               $checkUser = $this->checkSchedulerUser();
+               if ($checkUser == -1) {
+                       $link = $GLOBALS['MCONF']['_'] . '&SET[function]=check&CMD=user';
+                       $message = sprintf($GLOBALS['LANG']->getLL('msg.schedulerUserMissing'), htmlspecialchars($link));
+                       $severity = t3lib_FlashMessage::ERROR;
+               } elseif ($checkUser == 0) {
+                       $message = $GLOBALS['LANG']->getLL('msg.schedulerUserFoundButDisabled');
+                       $severity = t3lib_FlashMessage::WARNING;
+               } else {
+                       $message = $GLOBALS['LANG']->getLL('msg.schedulerUserFound');
+                       $severity = t3lib_FlashMessage::OK;
+               }
+               $flashMessage = t3lib_div::makeInstance(
+                       't3lib_FlashMessage',
+                       $message,
+                       '',
+                       $severity
+               );
+               $content .= $flashMessage->render() . '</div>';
+
+                       // Check if CLI script is executable or not
+               $script = PATH_typo3 . 'cli_dispatch.phpsh';
+               $isExecutable = FALSE;
+                       // Skip this check if running Windows, as rights do not work the same way on this platform
+                       // (i.e. the script will always appear as *not* executable)
+               if (TYPO3_OS === 'WIN') {
+                       $isExecutable = TRUE;
+               } else {
+                       $isExecutable = is_executable($script);
+               }
+               $content .= '<div class="info-block">';
+               $content .= '<h3>' . $GLOBALS['LANG']->getLL('hdg.cliScript') . '</h3>';
+               $content .= '<p>' . sprintf($GLOBALS['LANG']->getLL('msg.cliScript'), $script) . '</p>';
+
+               if ($isExecutable) {
+                       $message = $GLOBALS['LANG']->getLL('msg.cliScriptExecutable');
+                       $severity = t3lib_FlashMessage::OK;
+               } else {
+                       $message = $GLOBALS['LANG']->getLL('msg.cliScriptNotExecutable');
+                       $severity = t3lib_FlashMessage::ERROR;
+               }
+               $flashMessage = t3lib_div::makeInstance(
+                       't3lib_FlashMessage',
+                       $message,
+                       '',
+                       $severity
+               );
+               $content .= $flashMessage->render() . '</div>';
+
+               return $content;
+       }
+
+       /**
+        * This method gathers information about all available task classes and displays it
+        *
+        * @return      string  HTML content to display
+        */
+       protected function displayInfoScreen() {
+               $content = '';
+               $registeredClasses = self::getRegisteredClasses();
+
+                       // No classes available, display information message
+               if (count($registeredClasses) == 0) {
+                               /** @var t3lib_FlashMessage $flashMessage */
+                       $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage',
+                               $GLOBALS['LANG']->getLL('msg.noTasksDefined'),
+                               '',
+                               t3lib_FlashMessage::INFO
+                       );
+                       $content .= $flashMessage->render();
+
+                       // Display the list of all available classes
+               } else {
+                               // Initialise table layout
+                       $tableLayout = array (
+                               'table' => array ('<table border="0" cellspacing="1" cellpadding="2" class="typo3-dblist">', '</table>'),
+                               '0' => array (
+                                       'tr' => array('<tr class="t3-row-header" valign="top">', '</tr>'),
+                                       'defCol' => array('<td>', '</td>')
+                               ),
+                               'defRow' => array (
+                                       'tr' => array('<tr class="db_list_normal">', '</tr>'),
+                                       'defCol' => array('<td>', '</td>')
+                               )
+                       );
+                       $table = array();
+                       $tr = 0;
+
+                               // Header row
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.name');
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.extension');
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.description');
+                       $table[$tr][] = '';
+                       $tr++;
+
+                               // Display information about each service
+                       foreach ($registeredClasses as $class => $classInfo) {
+                               $table[$tr][] = $classInfo['title'];
+                               $table[$tr][] = $classInfo['extension'];
+                               $table[$tr][] = $classInfo['description'];
+                               $link = $GLOBALS['MCONF']['_'] . '&SET[function]=list&CMD=add&tx_scheduler[class]=' . $class;
+                               $table[$tr][] = '<a href="' . htmlspecialchars($link) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:new', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-document-new') . '</a>';
+                               $tr++;
+                       }
+
+                               // Render the table and return it
+                       $content  = '<div>' . $GLOBALS['LANG']->getLL('msg.infoScreenIntro') . '</div>';
+                       $content .= $this->doc->spacer(5);
+                       $content .= $this->doc->table($table, $tableLayout);
+               }
+
+               return $content;
+       }
+
+       /**
+        * Display the current server's time along with a help text about server time
+        * usage in the Scheduler
+        *
+        * @return      string  HTML to display
+        */
+       protected function displayServerTime() {
+                       // Get the current time, formatted
+               $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] . ' T (e';
+               $now = date($dateFormat) . ', GMT ' . date('P') . ')';
+                       // Display the help text
+               $serverTime  = '<h4>' . $GLOBALS['LANG']->getLL('label.serverTime') . '</h4>';
+               $serverTime .= '<p>' . $GLOBALS['LANG']->getLL('msg.serverTimeHelp') . '</p>';
+               $serverTime .= '<p>' . sprintf($GLOBALS['LANG']->getLL('msg.serverTime'), $now) . '</p>';
+               return $serverTime;
+       }
+
+       /**
+        * Delete a task from the execution queue
+        *
+        * @return      void
+        */
+       protected function deleteTask() {
+               try {
+                               // Try to fetch the task and delete it
+                               /**
+                                * @var tx_scheduler_Task
+                                */
+                       $task = $this->scheduler->fetchTask($this->submittedData['uid']);
+                               // If the task is currently running, it may not be deleted
+                       if ($task->isExecutionRunning()) {
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.maynotDeleteRunningTask'), t3lib_FlashMessage::ERROR);
+                       } else {
+                               if ($this->scheduler->removeTask($task)) {
+                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteSuccess'));
+                               } else {
+                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteError'), t3lib_FlashMessage::ERROR);
+                               }
+                       }
+               } catch (UnexpectedValueException $e) {
+                               // The task could not be unserialized properly, simply delete the database record
+                       $result = $GLOBALS['TYPO3_DB']->exec_DELETEquery('tx_scheduler_task', 'uid = ' . intval($this->submittedData['uid']));
+                       if ($result) {
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteSuccess'));
+                       } else {
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteError'), t3lib_FlashMessage::ERROR);
+                       }
+               } catch (OutOfBoundsException $e) {
+                               // The task was not found, for some reason
+                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR);
+               }
+       }
+
+       /**
+        * Clears the registered running executions from the task
+        * Note that this doesn't actually stop the running script. It just unmarks
+        * all executions.
+        * TODO: find a way to really kill the running task
+        *
+        * @return      void
+        */
+       protected function stopTask() {
+               try {
+                               // Try to fetch the task and stop it
+                               /**
+                                * @var tx_scheduler_Task
+                                */
+                       $task = $this->scheduler->fetchTask($this->submittedData['uid']);
+                       if ($task->isExecutionRunning()) {
+                               // If the task is indeed currently running, clear marked executions
+
+                               $result = $task->unmarkAllExecutions();
+                               if ($result) {
+                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.stopSuccess'));
+                               } else {
+                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.stopError'), t3lib_FlashMessage::ERROR);
+                               }
+                       } else {
+                               // The task is not running, nothing to unmark
+
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.maynotStopNonRunningTask'), t3lib_FlashMessage::WARNING);
+                       }
+               } catch (Exception $e) {
+                               // The task was not found, for some reason
+                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR);
+               }
+       }
+
+       /**
+        * Return a form to add a new task or edit an existing one
+        *
+        * @return      string  HTML form to add or edit a task
+        */
+       protected function editTask() {
+               $registeredClasses = self::getRegisteredClasses();
+               $content = '';
+               $taskInfo = array();
+               $task = NULL;
+               $process = 'edit';
+
+               if ($this->submittedData['uid'] > 0) {
+                               // If editing, retrieve data for existing task
+                       try {
+                               $taskRecord = $this->scheduler->fetchTaskRecord($this->submittedData['uid']);
+                                       // If there's a registered execution, the task should not be edited
+                               if (!empty($taskRecord['serialized_executions'])) {
+                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.maynotEditRunningTask'), t3lib_FlashMessage::ERROR);
+                                       throw new LogicException('Runnings tasks cannot not be edited', 1251232849);
+                               }
+                                       // Get the task object
+                               $task = unserialize($taskRecord['serialized_task_object']);
+
+                                       // Set some task information
+                               $class = $taskRecord['classname'];
+                               $taskInfo['disable'] = $taskRecord['disable'];
+
+                                       // Check that the task object is valid
+                               if ($this->scheduler->isValidTaskObject($task)) {
+                                       // The task object is valid, process with fetching current data
+
+                                       $taskInfo['class'] = $class;
+
+                                               // Get execution information
+                                       $taskInfo['start']    = $task->getExecution()->getStart();
+                                       $taskInfo['end']      = $task->getExecution()->getEnd();
+                                       $taskInfo['interval'] = $task->getExecution()->getInterval();
+                                       $taskInfo['croncmd']  = $task->getExecution()->getCronCmd();
+                                       $taskInfo['multiple'] = $task->getExecution()->getMultiple();
+
+                                       if (!empty($taskInfo['interval']) || !empty($taskInfo['croncmd'])) {
+                                                       // Guess task type from the existing information
+                                                       // If an interval or a cron command is defined, it's a recurring task
+
+                                                       // FIXME remove magic numbers for the type, use class constants instead
+                                               $taskInfo['type']      = 2;
+                                               $taskInfo['frequency'] = (empty($taskInfo['interval'])) ? $taskInfo['croncmd'] : $taskInfo['interval'];
+                                       } else {
+                                                       // It's not a recurring task
+                                                       // Make sure interval and cron command are both empty
+                                               $taskInfo['type']      = 1;
+                                               $taskInfo['frequency'] = '';
+                                               $taskInfo['end']       = 0;
+                                       }
+                               } else {
+                                       // The task object is not valid
+
+                                               // Issue error message
+                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.invalidTaskClassEdit'), $class), t3lib_FlashMessage::ERROR);
+                                               // Initialize empty values
+                                       $taskInfo['start']     = 0;
+                                       $taskInfo['end']       = 0;
+                                       $taskInfo['frequency'] = '';
+                                       $taskInfo['multiple']  = false;
+                                       $taskInfo['type']      = 1;
+                               }
+                       } catch (OutOfBoundsException $e) {
+                                       // Add a message and continue throwing the exception
+                               $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR);
+                               throw $e;
+                       }
+               } else {
+                               // If adding a new object, set some default values
+                       $taskInfo['class'] = key($registeredClasses);
+                       $taskInfo['type'] = 2;
+                       $taskInfo['start'] = $GLOBALS['EXEC_TIME'];
+                       $taskInfo['end'] = '';
+                       $taskInfo['frequency'] = '';
+                       $taskInfo['multiple'] = 0;
+                       $process = 'add';
+               }
+
+               if (count($this->submittedData) > 0) {
+                               // If some data was already submitted, use it to override
+                               // existing data
+                       $taskInfo = t3lib_div::array_merge_recursive_overrule($taskInfo, $this->submittedData);
+               }
+
+                       // Get the extra fields to display for each task that needs some
+               $allAdditionalFields = array();
+               if ($process == 'add') {
+                       foreach ($registeredClasses as $class => $registrationInfo) {
+                               if (!empty($registrationInfo['provider'])) {
+                                       $providerObject = t3lib_div::getUserObj($registrationInfo['provider']);
+                                       if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
+                                               $additionalFields = $providerObject->getAdditionalFields($taskInfo, NULL, $this);
+                                               $allAdditionalFields = array_merge($allAdditionalFields, array($class => $additionalFields));
+                                       }
+                               }
+                       }
+
+                       // In case of edit, get only the extra fields for the current task class
+               } else {
+                       if (!empty($registeredClasses[$taskInfo['class']]['provider'])) {
+                               $providerObject = t3lib_div::getUserObj($registeredClasses[$taskInfo['class']]['provider']);
+                               if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
+                                       $allAdditionalFields[$taskInfo['class']] = $providerObject->getAdditionalFields($taskInfo, $task, $this);
+                               }
+                       }
+               }
+
+                       // Load necessary JavaScript
+                       /** @var $pageRenderer t3lib_PageRenderer */
+               $pageRenderer = $this->doc->getPageRenderer();
+               $pageRenderer->loadExtJS();
+               $pageRenderer->addJsFile(t3lib_extMgm::extRelPath('scheduler') . 'res/tx_scheduler_be.js');
+               $pageRenderer->addJsFile($this->backPath . '../t3lib/js/extjs/tceforms.js');
+
+                       // Define settings for Date Picker
+               $typo3Settings = array(
+                       'datePickerUSmode' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? 1 : 0,
+                       'dateFormat'       => array('j-n-Y', 'G:i j-n-Y'),
+                       'dateFormatUS'     => array('n-j-Y', 'G:i n-j-Y'),
+               );
+               $pageRenderer->addInlineSettingArray('', $typo3Settings);
+
+                       // Define table layout for add/edit form
+               $tableLayout = array (
+                       'table' => array ('<table border="0" cellspacing="0" cellpadding="0" id="edit_form" class="typo3-usersettings">', '</table>'),
+               );
+
+                       // Define a style for hiding
+                       // Some fields will be hidden when the task is not recurring
+               $style = '';
+               if ($taskInfo['type'] == 1) {
+                       $style = ' style="display: none"';
+               }
+
+                       // Start rendering the add/edit form
+               $content .= '<input type="hidden" name="tx_scheduler[uid]" value="' . $this->submittedData['uid'] . '" />';
+               $content .= '<input type="hidden" name="previousCMD" value="' . $this->CMD . '" />';
+               $content .= '<input type="hidden" name="CMD" value="save" />';
+
+               $table = array();
+               $tr = 0;
+               $defaultCell = array('<td class="td-input">', '</td>');
+
+                       // Disable checkbox
+               $label = '<label for="task_disable">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:disable') . '</label>';
+               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_disable', $label);
+               $table[$tr][] =
+                       '<input type="hidden"   name="tx_scheduler[disable]" value="0" />
+                        <input type="checkbox" name="tx_scheduler[disable]" value="1" id="task_disable"' . ($taskInfo['disable'] == 1 ? ' checked="checked"' : '') . ' />';
+               $tableLayout[$tr] = array (
+                       'tr'     => array('<tr id="task_disable_row">', '</tr>'),
+                       'defCol' => $defaultCell,
+                       '0'      => array('<td class="td-label">', '</td>')
+               );
+               $tr++;
+
+                       // Task class selector
+               $label = '<label for="task_class">' . $GLOBALS['LANG']->getLL('label.class') . '</label>';
+               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_class', $label);
+                       // On editing, don't allow changing of the task class, unless it was not valid
+               if ($this->submittedData['uid'] > 0 && !empty($taskInfo['class'])) {
+                       $cell = $registeredClasses[$taskInfo['class']]['title'] . ' (' . $registeredClasses[$taskInfo['class']]['extension'] . ')';
+                       $cell .= '<input type="hidden" name="tx_scheduler[class]" id="task_class" value="' . $taskInfo['class'] . '" />';
+               } else {
+                       $cell = '<select name="tx_scheduler[class]" id="task_class" class="wide" onchange="actOnChangedTaskClass(this)">';
+                               // Loop on all registered classes to display a selector
+                       foreach ($registeredClasses as $class => $classInfo) {
+                               $selected = ($class == $taskInfo['class']) ? ' selected="selected"' : '';
+                               $cell .= '<option value="' . $class . '"' . $selected . '>' . $classInfo['title'] . ' (' . $classInfo['extension'] . ')' . '</option>';
+                       }
+                       $cell .= '</select>';
+               }
+               $table[$tr][] = $cell;
+                       // Make sure each row has a unique id, for manipulation with JS
+               $tableLayout[$tr] = array (
+                       'tr'     => array('<tr id="task_class_row">', '</tr>'),
+                       'defCol' => $defaultCell,
+                       '0'      => array('<td class="td-label">', '</td>')
+               );
+               $tr++;
+
+                       // Task type selector
+               $label = '<label for="task_type">' . $GLOBALS['LANG']->getLL('label.type') . '</label>';
+               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_type', $label);
+               $table[$tr][] =
+                       '<select name="tx_scheduler[type]" id="task_type" onchange="actOnChangedTaskType(this)">' .
+                               '<option value="1"' . ($taskInfo['type'] == 1 ? ' selected="selected"' : '') . '>' . $GLOBALS['LANG']->getLL('label.type.single') . '</option>' .
+                               '<option value="2"' . ($taskInfo['type'] == 2 ? ' selected="selected"' : '') . '>' . $GLOBALS['LANG']->getLL('label.type.recurring') . '</option>' .
+                       '</select>';
+               $tableLayout[$tr] = array (
+                       'tr'     => array('<tr id="task_type_row">', '</tr>'),
+                       'defCol' => $defaultCell,
+                       '0'      => array('<td class="td-label">', '</td>'),
+               );
+               $tr++;
+
+                       // Start date/time field
+                       // NOTE: datetime fields need a special id naming scheme
+               $label = '<label for="tceforms-datetimefield-task_start">' . $GLOBALS['LANG']->getLL('label.start') . '</label>';
+               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_start', $label);
+               $table[$tr][] = '<input name="tx_scheduler[start]" type="text" id="tceforms-datetimefield-task_start" value="' . ((empty($taskInfo['start'])) ? '' : strftime('%H:%M %d-%m-%Y', $taskInfo['start'])) . '" />' .
+                       t3lib_iconWorks::getSpriteIcon(
+                               'actions-edit-pick-date',
+                               array(
+                                       'style' => 'cursor:pointer;',
+                                       'id' => 'picker-tceforms-datetimefield-task_start'
+                               )
+                       );
+               $tableLayout[$tr] = array (
+                       'tr' => array('<tr id="task_start_row">', '</tr>'),
+                       'defCol' => $defaultCell,
+                       '0'      => array('<td class="td-label">', '</td>')
+               );
+               $tr++;
+
+                       // End date/time field
+                       // NOTE: datetime fields need a special id naming scheme
+               $label = '<label for="tceforms-datetimefield-task_end">' . $GLOBALS['LANG']->getLL('label.end') . '</label>';
+               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_end', $label);
+               $table[$tr][] = '<input name="tx_scheduler[end]" type="text" id="tceforms-datetimefield-task_end" value="' . ((empty($taskInfo['end'])) ? '' : strftime('%H:%M %d-%m-%Y', $taskInfo['end'])) . '" />' .
+                       t3lib_iconWorks::getSpriteIcon(
+                               'actions-edit-pick-date',
+                               array(
+                                       'style' => 'cursor:pointer;',
+                                       'id' => 'picker-tceforms-datetimefield-task_end'
+                               )
+                       );
+               $tableLayout[$tr] = array (
+                       'tr'     => array('<tr id="task_end_row"' . $style . '>', '</tr>'),
+                       'defCol' => $defaultCell,
+                       '0'      => array('<td class="td-label">', '</td>'),
+               );
+               $tr++;
+
+                       // Frequency input field
+               $label = '<label for="task_frequency">' . $GLOBALS['LANG']->getLL('label.frequency.long') . '</label>';
+               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_frequency', $label);
+               $cell = '<input type="text" name="tx_scheduler[frequency]" id="task_frequency" value="' . $taskInfo['frequency'] . '" />';
+               $table[$tr][] = $cell;
+               $tableLayout[$tr] = array (
+                       'tr'     => array('<tr id="task_frequency_row"' . $style . '>', '</tr>'),
+                       'defCol' => $defaultCell,
+                       '0'      => array('<td class="td-label">', '</td>'),
+               );
+               $tr++;
+
+                       // Multiple execution selector
+               $label = '<label for="task_multiple">' . $GLOBALS['LANG']->getLL('label.parallel.long') . '</label>';
+               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_multiple', $label);
+               $table[$tr][] =
+                       '<input type="hidden"   name="tx_scheduler[multiple]" value="0" />
+                        <input type="checkbox" name="tx_scheduler[multiple]" value="1" id="task_multiple"' . ($taskInfo['multiple'] == 1 ? ' checked="checked"' : '') . ' />';
+               $tableLayout[$tr] = array (
+                       'tr'     => array('<tr id="task_multiple_row"' . $style . '>', '</tr>'),
+                       'defCol' => $defaultCell,
+                       '0'      => array('<td class="td-label">', '</td>')
+               );
+               $tr++;
+
+                       // Display additional fields
+               foreach ($allAdditionalFields as $class => $fields) {
+                       if ($class == $taskInfo['class']) {
+                               $additionalFieldsStyle = '';
+                       } else {
+                               $additionalFieldsStyle = ' style="display: none"';
+                       }
+
+                               // Add each field to the display, if there are indeed any
+                       if (isset($fields) && is_array($fields)) {
+                               foreach ($fields as $fieldID => $fieldInfo) {
+                                       $label = '<label for="' . $fieldID . '">' . $GLOBALS['LANG']->sL($fieldInfo['label']) . '</label>';
+                                       $table[$tr][] = t3lib_BEfunc::wrapInHelp($fieldInfo['cshKey'], $fieldInfo['cshLabel'], $label);
+                                       $table[$tr][] = $fieldInfo['code'];
+                                       $tableLayout[$tr] = array (
+                                               'tr'     => array('<tr id="' . $fieldID . '_row"' . $additionalFieldsStyle .' class="extraFields extra_fields_' . $class . '">', '</tr>'),
+                                               'defCol' => $defaultCell,
+                                               '0'      => array('<td class="td-label">', '</td>')
+                                       );
+                                       $tr++;
+                               }
+                       }
+               }
+
+                       // Render the add/edit task form
+               $content .= '<div style="float: left;"><div class="typo3-dyntabmenu-divs">';
+               $content .= $this->doc->table($table, $tableLayout);
+               $content .= '</div></div>';
+
+               $content .= '<div style="padding-top: 20px; clear: both;"></div><div><input type="submit" name="save" class="button" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:save', TRUE) . '" /> '
+                       . '<input type="button" name="cancel" class="button" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:cancel', TRUE) . '" onclick="document.location=\'' . $GLOBALS['MCONF']['_'] . '\'" /></div>';
+
+                       // Display information about server time usage
+               $content .= $this->displayServerTime();
+
+               return $content;
+       }
+
+       /**
+        * Execute all selected tasks
+        *
+        * @return      void
+        */
+       protected function executeTasks() {
+                       // Continue if some elements have been chosen for execution
+               if (isset($this->submittedData['execute']) && count($this->submittedData['execute']) > 0) {
+
+                               // Get list of registered classes
+                       $registeredClasses = self::getRegisteredClasses();
+
+                               // Loop on all selected tasks
+                       foreach ($this->submittedData['execute'] as $uid) {
+
+                               try {
+                                               // Try fetching the task
+                                       $task = $this->scheduler->fetchTask($uid);
+                                       $class = get_class($task);
+                                       $name = $registeredClasses[$class]['title']. ' (' . $registeredClasses[$class]['extension'] . ')';
+                                               // Now try to execute it and report on outcome
+                                       try {
+                                               $result = $this->scheduler->executeTask($task);
+                                               if ($result) {
+                                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.executed'), $name));
+                                               } else {
+                                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.notExecuted'), $name), t3lib_FlashMessage::ERROR);
+                                               }
+                                       }
+                                       catch (Exception $e) {
+                                                       // An exception was thrown, display its message as an error
+                                               $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.executionFailed'), $name, $e->getMessage()), t3lib_FlashMessage::ERROR);
+                                       }
+                               }
+                                       // The task was not found, for some reason
+                               catch (OutOfBoundsException $e) {
+                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $uid), t3lib_FlashMessage::ERROR);
+                               }
+                                       // The task object was not valid
+                               catch (UnexpectedValueException $e) {
+                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.executionFailed'), $name, $e->getMessage()), t3lib_FlashMessage::ERROR);
+                               }
+                       }
+                               // Record the run in the system registry
+                       $this->scheduler->recordLastRun('manual');
+                               // Make sure to switch to list view after execution
+                       $this->CMD = 'list';
+               }
+       }
+
+       /**
+        * Assemble display of list of scheduled tasks
+        *
+        * @return      string                  table of waiting schedulings
+        */
+       protected function listTasks() {
+                       // Define display format for dates
+               $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
+               $content = '';
+
+                       // Get list of registered classes
+               $registeredClasses = self::getRegisteredClasses();
+
+                       // Get all registered tasks
+               $query = array(
+                       'SELECT'  => '*',
+                       'FROM'    => 'tx_scheduler_task',
+                       'WHERE'   => '1=1',
+                       'ORDERBY' => 'nextexecution'
+               );
+
+               $res = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($query);
+               $numRows = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
+                       // No tasks defined, display information message
+               if ($numRows == 0) {
+                               /** @var t3lib_FlashMessage $flashMessage */
+                       $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage',
+                               $GLOBALS['LANG']->getLL('msg.noTasks'),
+                               '',
+                               t3lib_FlashMessage::INFO
+                       );
+                       $content .= $flashMessage->render();
+               } else {
+                               // Load ExtJS framework and specific JS library
+                               /** @var $pageRenderer t3lib_PageRenderer */
+                       $pageRenderer = $this->doc->getPageRenderer();
+                       $pageRenderer->loadExtJS();
+                       $pageRenderer->addJsFile(t3lib_extMgm::extRelPath('scheduler') . 'res/tx_scheduler_be.js');
+
+                               // Initialise table layout
+                       $tableLayout = array(
+                               'table' => array(
+                                       '<table border="0" cellspacing="1" cellpadding="2" class="typo3-dblist">', '</table>'
+                               ),
+                               '0'     => array(
+                                       'tr'     => array('<tr class="t3-row-header">', '</tr>'),
+                                       'defCol' => array('<td>', '</td>'),
+                                       '1'      => array('<td style="width: 36px;">', '</td>'),
+                                       '3'      => array('<td colspan="2">', '</td>'),
+                               ),
+                               'defRow' => array(
+                                       'tr'     => array('<tr class="db_list_normal">', '</tr>'),
+                                       'defCol' => array('<td>', '</td>'),
+                                       '1'      => array('<td class="right">', '</td>'),
+                                       '2'      => array('<td class="right">', '</td>'),
+                               )
+                       );
+                       $disabledTaskRow = array (
+                               'tr'     => array('<tr class="db_list_normal disabled">', '</tr>'),
+                               'defCol' => array('<td>', '</td>'),
+                               '1'      => array('<td class="right">', '</td>'),
+                               '2'      => array('<td class="right">', '</td>'),
+                       );
+                       $rowWithSpan = array (
+                               'tr'     => array('<tr class="db_list_normal">', '</tr>'),
+                               'defCol' => array('<td>', '</td>'),
+                               '1'      => array('<td class="right">', '</td>'),
+                               '2'      => array('<td class="right">', '</td>'),
+                               '3'      => array('<td colspan="6">', '</td>'),
+                       );
+                       $table = array();
+                       $tr = 0;
+
+                               // Header row
+                       $table[$tr][] = '<a href="#" onclick="toggleCheckboxes();" title="' . $GLOBALS['LANG']->getLL('label.checkAll', TRUE) . '" class="icon">' .
+                               t3lib_iconWorks::getSpriteIcon('actions-document-select') .
+                               '</a>';
+                       $table[$tr][] = '&nbsp;';
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.id');
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('task');
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.type');
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.frequency');
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.parallel');
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.lastExecution');
+                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.nextExecution');
+                       $tr++;
+
+                               // Loop on all tasks
+                       while (($schedulerRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))) {
+                                       // Define action icons
+                               $editAction = '<a href="' . $GLOBALS['MCONF']['_'] . '&CMD=edit&tx_scheduler[uid]=' . $schedulerRecord['uid'] . '" title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:edit', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-document-open') . '</a>';
+                               $deleteAction = '<a href="' . $GLOBALS['MCONF']['_'] . '&CMD=delete&tx_scheduler[uid]=' . $schedulerRecord['uid'] . '" onclick="return confirm(\'' . $GLOBALS['LANG']->getLL('msg.delete') . '\');" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:delete', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-edit-delete') . '</a>';
+                               $stopAction = '<a href="' . $GLOBALS['MCONF']['_'] . '&CMD=stop&tx_scheduler[uid]=' . $schedulerRecord['uid'] . '" onclick="return confirm(\'' . $GLOBALS['LANG']->getLL('msg.stop') . '\');" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:stop', TRUE) . '" class="icon"><img ' . t3lib_iconWorks::skinImg($this->backPath, t3lib_extMgm::extRelPath('scheduler') . '/res/gfx/stop.png') . ' alt="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:stop') . '" /></a>';
+                                       // Define some default values
+                               $lastExecution = '-';
+                               $isRunning = false;
+                               $executionStatus = 'scheduled';
+                               $executionStatusDetail = '';
+                               $executionStatusOutput = '';
+                               $name = '';
+                               $nextDate = '-';
+                               $execType = '-';
+                               $frequency = '-';
+                               $multiple = '-';
+                               $startExecutionElement = '&nbsp;';
+
+                                       // Restore the serialized task and pass it a reference to the scheduler object
+                               $task = unserialize($schedulerRecord['serialized_task_object']);
+
+                                       // Assemble information about last execution
+                               $context = '';
+                               if (!empty($schedulerRecord['lastexecution_time'])) {
+                                       $lastExecution = date($dateFormat, $schedulerRecord['lastexecution_time']);
+                                       if ($schedulerRecord['lastexecution_context'] == 'CLI') {
+                                               $context = $GLOBALS['LANG']->getLL('label.cron');
+                                       } else {
+                                               $context = $GLOBALS['LANG']->getLL('label.manual');
+                                       }
+                                       $lastExecution .= ' (' . $context . ')';
+                               }
+
+                               if ($this->scheduler->isValidTaskObject($task)) {
+                                       // The task object is valid
+
+                                       $name = htmlspecialchars($registeredClasses[$schedulerRecord['classname']]['title']. ' (' . $registeredClasses[$schedulerRecord['classname']]['extension'] . ')');
+                                       $additionalInformation = $task->getAdditionalInformation();
+                                       if (!empty($additionalInformation)) {
+                                               $name .= '<br />[' . htmlspecialchars($additionalInformation) . ']';
+                                       }
+
+                                               // Check if task currently has a running execution
+                                       if (!empty($schedulerRecord['serialized_executions'])) {
+                                               $isRunning = true;
+                                               $executionStatus = 'running';
+                                       }
+
+                                               // Prepare display of next execution date
+                                               // If task is currently running, date is not displayed (as next hasn't been calculated yet)
+                                               // Also hide the date if task is disabled (the information doesn't make sense, as it will not run anyway)
+                                       if ($isRunning || $schedulerRecord['disable'] == 1) {
+                                               $nextDate = '-';
+                                       }
+                                       else {
+                                               $nextDate = date($dateFormat, $schedulerRecord['nextexecution']);
+                                               if (empty($schedulerRecord['nextexecution'])) {
+                                                       $nextDate = $GLOBALS['LANG']->getLL('none');
+                                               } elseif ($schedulerRecord['nextexecution'] < $GLOBALS['EXEC_TIME']) {
+                                                               // Next execution is overdue, highlight date
+                                                       $nextDate = '<span class="late" title="' . $GLOBALS['LANG']->getLL('status.legend.scheduled') . '">' . $nextDate . '</span>';
+                                                       $executionStatus = 'late';
+                                               }
+                                       }
+
+                                               // Get execution type
+                                       if ($task->getExecution()->getInterval() == 0 && $task->getExecution()->getCronCmd() == '') {
+                                               $execType = $GLOBALS['LANG']->getLL('label.type.single');
+                                               $frequency = '-';
+                                       } else {
+                                               $execType = $GLOBALS['LANG']->getLL('label.type.recurring');
+                                               if ($task->getExecution()->getCronCmd() == '') {
+                                                       $frequency = $task->getExecution()->getInterval();
+                                               } else {
+                                                       $frequency = $task->getExecution()->getCronCmd();
+                                               }
+                                       }
+
+                                               // Get multiple executions setting
+                                       if ($task->getExecution()->getMultiple()) {
+                                               $multiple = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes');
+                                       } else {
+                                               $multiple = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:no');
+                                       }
+
+                                               // Define checkbox
+                                       $startExecutionElement = '<input type="checkbox" name="tx_scheduler[execute][]" value="' . $schedulerRecord['uid'] . '" id="task_' . $schedulerRecord['uid'] . '" class="checkboxes" />';
+
+                                               // Show no action links (edit, delete) if task is running
+                                       $actions = $editAction . $deleteAction;
+                                       if ($isRunning) {
+                                               $actions = $stopAction;
+                                       }
+
+                                               // Check the disable status
+                                               // Row is shown dimmed if task is disabled, unless it is still running
+                                       if ($schedulerRecord['disable'] == 1 && !$isRunning) {
+                                               $tableLayout[$tr] = $disabledTaskRow;
+                                               $executionStatus  = 'disabled';
+                                       }
+
+                                               // Check if the last run failed
+                                       $failureOutput = '';
+                                       if (!empty($schedulerRecord['lastexecution_failure'])) {
+                                                       // Try to get the stored exception object
+                                               $exception = unserialize($schedulerRecord['lastexecution_failure']);
+                                                       // If the exception could not be unserialized, issue a default error message
+                                               if ($exception === FALSE) {
+                                                       $failureDetail = $GLOBALS['LANG']->getLL('msg.executionFailureDefault');
+                                               } else {
+                                                       $failureDetail = sprintf($GLOBALS['LANG']->getLL('msg.executionFailureReport'), $exception->getCode(), $exception->getMessage());
+                                               }
+                                               $failureOutput = ' <img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_failure.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.failure')) . '" title="' . htmlspecialchars($failureDetail) . '" />';
+                                       }
+
+                                               // Format the execution status,
+                                               // including failure feedback, if any
+                                       $executionStatusOutput = '<img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_' . $executionStatus . '.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.' . $executionStatus)) . '" title="' . htmlspecialchars($executionStatusDetail) . '" />' . $failureOutput;
+
+                                       $table[$tr][] = $startExecutionElement;
+                                       $table[$tr][] = $actions;
+                                       $table[$tr][] = $schedulerRecord['uid'];
+                                       $table[$tr][] = $executionStatusOutput;
+                                       $table[$tr][] = $name;
+                                       $table[$tr][] = $execType;
+                                       $table[$tr][] = $frequency;
+                                       $table[$tr][] = $multiple;
+                                       $table[$tr][] = $lastExecution;
+                                       $table[$tr][] = $nextDate;
+
+                               } else {
+                                       // The task object is not valid
+                                       // Prepare to issue an error
+
+                                               /** @var t3lib_FlashMessage $flashMessage */
+                                       $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage',
+                                               sprintf($GLOBALS['LANG']->getLL('msg.invalidTaskClass'), $schedulerRecord['classname']),
+                                               '',
+                                               t3lib_FlashMessage::ERROR
+                                       );
+                                       $executionStatusOutput = $flashMessage->render();
+
+                                       $tableLayout[$tr] = $rowWithSpan;
+                                       $table[$tr][] = $startExecutionElement;
+                                       $table[$tr][] = $deleteAction;
+                                       $table[$tr][] = $schedulerRecord['uid'];
+                                       $table[$tr][] = $executionStatusOutput;
+                               }
+
+                               $tr++;
+                       }
+                               // Render table
+                       $content .= $this->doc->table($table, $tableLayout);
+
+                       $content .= '<input type="submit" class="button" name="go" value="' . $GLOBALS['LANG']->getLL('label.executeSelected') . '" />';
+               }
+
+               if (count($registeredClasses) > 0) {
+                               // Display add new task link
+                       $link = $GLOBALS['MCONF']['_'] . '&CMD=add';
+                       $content .= '<p><a href="' . htmlspecialchars($link) .'"><img '
+                               . t3lib_iconWorks::skinImg($this->backPath, 'gfx/new_el.gif')
+                               . ' alt="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:new', TRUE)
+                               . '" /> ' . $GLOBALS['LANG']->getLL('action.add') . '</a></p>';
+               } else {
+                               /** @var t3lib_FlashMessage $flashMessage */
+                       $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage',
+                               $GLOBALS['LANG']->getLL('msg.noTasksDefined'),
+                               '',
+                               t3lib_FlashMessage::INFO
+                       );
+                       $content .= $flashMessage->render();
+               }
+
+                       // Display legend, if there's at least one registered task
+                       // Also display information about the usage of server time
+               if ($numRows > 0) {
+                       $content .= $this->doc->spacer(20);
+                       $content .= '<h4>' . $GLOBALS['LANG']->getLL('status.legend') . '</h4>
+                       <ul>
+                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_failure.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.failure')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.failure') . '</li>
+                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_late.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.late')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.late') . '</li>
+                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_running.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.running')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.running') . '</li>
+                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_scheduled.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.scheduled')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.scheduled') . '</li>
+                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_disabled.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.disabled')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.disabled') . '</li>
+                       </ul>';
+                       $content .= $this->doc->spacer(10);
+                       $content .= $this->displayServerTime();
+               }
+
+
+               $GLOBALS['TYPO3_DB']->sql_free_result($res);
+
+               return $content;
+       }
+
+       /**
+        * Saves a task specified in the backend form to the database
+        *
+        * @return      void
+        */
+       protected function saveTask() {
+
+                       // If a task is being edited fetch old task data
+               if (!empty($this->submittedData['uid'])) {
+                       try {
+                               $taskRecord = $this->scheduler->fetchTaskRecord($this->submittedData['uid']);
+                               /**
+                                * @var tx_scheduler_Task
+                                */
+                               $task = unserialize($taskRecord['serialized_task_object']);
+                       } catch (OutOfBoundsException $e) {
+                                       // If the task could not be fetched, issue an error message
+                                       // and exit early
+                               $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR);
+                               return;
+                       }
+
+                               // Register single execution
+                       if ($this->submittedData['type'] == 1) {
+                               $task->registerSingleExecution($this->submittedData['start']);
+
+                               // Else, it's a recurring task
+                       } else {
+                               if (!empty($this->submittedData['croncmd'])) {
+                                               // Definition by cron-like syntax
+
+                                       $interval = 0;
+                                       $cronCmd = $this->submittedData['croncmd'];
+                               } else {
+                                               // Definition by interval
+
+                                       $interval = $this->submittedData['interval'];
+                                       $cronCmd = '';
+                               }
+
+                                       // Register recurring execution
+                               $task->registerRecurringExecution($this->submittedData['start'], $interval, $this->submittedData['end'], $this->submittedData['multiple'], $cronCmd);
+                       }
+
+                               // Set disable flag
+                       $task->setDisabled($this->submittedData['disable']);
+
+                               // Save additional input values
+                       if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) {
+                               $providerObject = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']);
+                               if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
+                                       $providerObject->saveAdditionalFields($this->submittedData, $task);
+                               }
+                       }
+
+                               // Save to database
+                       $result = $this->scheduler->saveTask($task);
+                       if ($result) {
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.updateSuccess'));
+                       } else {
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.updateError'), t3lib_FlashMessage::ERROR);
+                       }
+               } else {
+                               // A new task is being created
+
+                               // Create an instance of chosen class
+                       $task = t3lib_div::makeInstance($this->submittedData['class']);
+
+                       if ($this->submittedData['type'] == 1) {
+                                       // Set up single execution
+                               $task->registerSingleExecution($this->submittedData['start']);
+                       } else {
+                                       // Set up recurring execution
+                               $task->registerRecurringExecution($this->submittedData['start'], $this->submittedData['interval'], $this->submittedData['end'], $this->submittedData['multiple'], $this->submittedData['croncmd']);
+                       }
+
+                               // Save additional input values
+                       if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) {
+                               $providerObject = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']);
+                               if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
+                                       $providerObject->saveAdditionalFields($this->submittedData, $task);
+                               }
+                       }
+
+                               // Set disable flag
+                       $task->setDisabled($this->submittedData['disable']);
+
+                               // Add to database
+                       $result = $this->scheduler->addTask($task);
+                       if ($result) {
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.addSuccess'));
+                       } else {
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.addError'), t3lib_FlashMessage::ERROR);
+                       }
+               }
+       }
+
+
+       /*************************
+        *
+        * INPUT PROCESSING UTILITIES
+        *
+        *************************/
+
+       /**
+        * Checks the submitted data and performs some preprocessing on it
+        *
+        * @return      boolean         True if everything was ok, false otherwise
+        */
+       protected function preprocessData() {
+               $result = true;
+
+                       // Validate id
+               $this->submittedData['uid'] = (empty($this->submittedData['uid'])) ? 0 : intval($this->submittedData['uid']);
+
+                       // Validate selected task class
+               if (!class_exists($this->submittedData['class'])) {
+                       $this->addMessage($GLOBALS['LANG']->getLL('msg.noTaskClassFound'), t3lib_FlashMessage::ERROR);
+               }
+
+                       // Check start date
+               if (empty($this->submittedData['start'])) {
+                       $this->addMessage($GLOBALS['LANG']->getLL('msg.noStartDate'), t3lib_FlashMessage::ERROR);
+                       $result = false;
+               } else {
+                       try {
+                               $timestamp = $this->checkDate($this->submittedData['start']);
+                               $this->submittedData['start'] = $timestamp;
+                       } catch (Exception $e) {
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.invalidStartDate'), t3lib_FlashMessage::ERROR);
+                               $result = false;
+                       }
+               }
+
+                       // Check end date, if recurring task
+               if ($this->submittedData['type'] == 2 && !empty($this->submittedData['end'])) {
+                       try {
+                               $timestamp = $this->checkDate($this->submittedData['end']);
+                               $this->submittedData['end'] = $timestamp;
+
+                               if ($this->submittedData['end'] < $this->submittedData['start']) {
+                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.endDateSmallerThanStartDate'), t3lib_FlashMessage::ERROR);
+                                       $result = false;
+                               }
+                       } catch (Exception $e) {
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.invalidEndDate'), t3lib_FlashMessage::ERROR);
+                               $result = false;
+                       }
+               }
+
+                       // Set default values for interval and cron command
+               $this->submittedData['interval'] = 0;
+               $this->submittedData['croncmd'] = '';
+
+                       // Check type and validity of frequency, if recurring
+               if ($this->submittedData['type'] == 2) {
+                       $frequency = trim($this->submittedData['frequency']);
+
+                       if (empty($frequency)) {
+                                       // Empty frequency, not valid
+
+                               $this->addMessage($GLOBALS['LANG']->getLL('msg.noFrequency'), t3lib_FlashMessage::ERROR);
+                               $result = FALSE;
+                       } else {
+                               $cronErrorCode = 0;
+                               $cronErrorMessage = '';
+
+                                       // Try interpreting the cron command
+                               try {
+                                       tx_scheduler_CronCmd_Normalize::normalize($frequency);
+                                       $this->submittedData['croncmd'] = $frequency;
+                               }
+                                       // If the cron command was invalid, we may still have a valid frequency in seconds
+                               catch (Exception $e) {
+                                               // Store the exception's result
+                                       $cronErrorMessage = $e->getMessage();
+                                       $cronErrorCode = $e->getCode();
+                                               // Check if the frequency is a valid number
+                                               // If yes, assume it is a frequency in seconds, and unset cron error code
+                                       if (is_numeric($frequency)) {
+                                               $this->submittedData['interval'] = intval($frequency);
+                                               unset($cronErrorCode);
+                                       }
+                               }
+                                       // If there's a cron error code, issue validation error message
+                               if (!empty($cronErrorCode)) {
+                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.frequencyError'), $cronErrorMessage, $cronErrorCode), t3lib_FlashMessage::ERROR);
+                                       $result = FALSE;
+                               }
+                       }
+               }
+
+                       // Validate additional input fields
+               if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) {
+                       $providerObject = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']);
+                       if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
+                                       // The validate method will return true if all went well, but that must not
+                                       // override previous false values => AND the returned value with the existing one
+                               $result &= $providerObject->validateAdditionalFields($this->submittedData, $this);
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
+        * This method checks whether the given string can be considered a valid date or not
+        * Allowed values are anything that matches natural language (see PHP function strtotime())
+        * or TYPO3's date syntax: HH:ii yyyy-mm-dd
+        * If the string is a valid date, the corresponding timestamp is returned.
+        * Otherwise an exception is thrown
+        *
+        * @param       string          $string: string to check
+        * @return      integer         Unix timestamp
+        */
+       protected function checkDate($string) {
+                       // Try with strtotime
+               $timestamp = strtotime($string);
+
+                       // That failed. Try TYPO3's standard date/time input format
+               if ($timestamp === false) {
+                               // Split time and date
+                       $dateParts = t3lib_div::trimExplode(' ', $string, true);
+                               // Proceed if there are indeed two parts
+                               // Extract each component of date and time
+                       if (count($dateParts) == 2) {
+                               list($time, $date) = $dateParts;
+                               list($hour, $minutes) = t3lib_div::trimExplode(':', $time, true);
+                               list($day, $month, $year) = t3lib_div::trimExplode('-', $date, true);
+                                       // Get a timestamp from all these parts
+                               $timestamp = mktime($hour, $minutes, 0, $month, $day, $year);
+                       }
+                               // If the timestamp is still false, throw an exception
+                       if ($timestamp === false) {
+                               throw new InvalidArgumentException('"' . $string . '" seems not to be a correct date.', 1294587694);
+                       }
+               }
+               return $timestamp;
+       }
+
+       /*************************
+        *
+        * APPLICATION LOGIC UTILITIES
+        *
+        *************************/
+
+       /**
+        * This method is used to add a message to the internal queue
+        *
+        * @param       string  the message itself
+        * @param       integer message level (-1 = success (default), 0 = info, 1 = notice, 2 = warning, 3 = error)
+        * @return      void
+        */
+       public function addMessage($message, $severity = t3lib_FlashMessage::OK) {
+               $message = t3lib_div::makeInstance(
+                       't3lib_FlashMessage',
+                       $message,
+                       '',
+                       $severity
+               );
+
+               t3lib_FlashMessageQueue::addMessage($message);
+       }
+
+       /**
+        * This method a list of all classes that have been registered with the Scheduler
+        * For each item the following information is provided, as an associative array:
+        *
+        * ['extension']        =>      Key of the extension which provides the class
+        * ['filename']         =>      Path to the file containing the class
+        * ['title']            =>      String (possibly localized) containing a human-readable name for the class
+        * ['provider']         =>      Name of class that implements the interface for additional fields, if necessary
+        *
+        * The name of the class itself is used as the key of the list array
+        *
+        * @return      array   List of registered classes
+        */
+       protected static function getRegisteredClasses() {
+               $list = array();
+               if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'])) {
+                       foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] as $class => $registrationInformation) {
+
+                               $title         = isset($registrationInformation['title'])         ? $GLOBALS['LANG']->sL($registrationInformation['title'])         : '';
+                               $description   = isset($registrationInformation['description'])   ? $GLOBALS['LANG']->sL($registrationInformation['description'])   : '';
+
+                               $list[$class] = array(
+                                       'extension'     => $registrationInformation['extension'],
+                                       'title'         => $title,
+                                       'description'   => $description,
+                                       'provider'              => isset($registrationInformation['additionalFields']) ? $registrationInformation['additionalFields'] : ''
+                               );
+                       }
+               }
+
+               return $list;
+       }
+
+
+       /*************************
+        *
+        * RENDERING UTILITIES
+        *
+        *************************/
+
+       /**
+        * Gets the filled markers that are used in the HTML template.
+        *
+        * @return      array           The filled marker array
+        */
+       protected function getTemplateMarkers() {
+               $markers = array(
+                       'CSH' => t3lib_BEfunc::wrapInHelp('_MOD_tools_txschedulerM1', ''),
+                       'FUNC_MENU' => $this->getFunctionMenu(),
+                       'CONTENT'   => $this->content,
+                       'TITLE'     => $GLOBALS['LANG']->getLL('title'),
+               );
+
+               return $markers;
+       }
+
+       /**
+        * Gets the function menu selector for this backend module.
+        *
+        * @return      string          The HTML representation of the function menu selector
+        */
+       protected function getFunctionMenu() {
+               $functionMenu = t3lib_BEfunc::getFuncMenu(
+                       0,
+                       'SET[function]',
+                       $this->MOD_SETTINGS['function'],
+                       $this->MOD_MENU['function']
+               );
+
+               return $functionMenu;
+       }
+
+       /**
+        * Gets the buttons that shall be rendered in the docHeader.
+        *
+        * @return      array           Available buttons for the docHeader
+        */
+       protected function getDocHeaderButtons() {
+               $buttons = array(
+                       'reload'   => '',
+                       'shortcut' => $this->getShortcutButton(),
+               );
+
+               if (empty($this->CMD) || $this->CMD == 'list') {
+                       $buttons['reload'] = '<a href="' . $GLOBALS['MCONF']['_'] . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.reload', TRUE) . '">' .
+                         t3lib_iconWorks::getSpriteIcon('actions-system-refresh') .
+                 '</a>';
+               }
+
+               return $buttons;
+       }
+
+       /**
+        * Gets the button to set a new shortcut in the backend (if current user is allowed to).
+        *
+        * @return      string          HTML representiation of the shortcut button
+        */
+       protected function getShortcutButton() {
+               $result = '';
+               if ($GLOBALS['BE_USER']->mayMakeShortcut()) {
+                       $result = $this->doc->makeShortcutIcon('', 'function', $this->MCONF['name']);
+               }
+
+               return $result;
+       }
+}
+
+if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/scheduler/class.tx_scheduler_module.php'])) {
+       include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/scheduler/class.tx_scheduler_module.php']);
+}
+?>
\ No newline at end of file
index 5aa8482..6c3ada4 100644 (file)
@@ -15,7 +15,7 @@ return array(
        'tx_scheduler_testtask' => $extensionPath . 'examples/class.tx_scheduler_testtask.php',
        'tx_scheduler_testtask_additionalfieldprovider' => $extensionPath . 'examples/class.tx_scheduler_testtask_additionalfieldprovider.php',
        'tx_scheduler_additionalfieldprovider' => $extensionPath . 'interfaces/interface.tx_scheduler_additionalfieldprovider.php',
-       'tx_scheduler_module' => $extensionPath . 'mod1/index.php',
+       'tx_scheduler_module' => $extensionPath . 'class.tx_scheduler_module.php',
        'tx_scheduler_croncmdtest' => $extensionPath . 'tests/tx_scheduler_croncmdTest.php',
        'tx_scheduler_cachingframeworkgarbagecollection' => $extensionPath . 'tasks/class.tx_scheduler_cachingframeworkgarbagecollection.php',
        'tx_scheduler_cachingframeworkgarbagecollection_additionalfieldprovider' => $extensionPath . 'tasks/class.tx_scheduler_cachingframeworkgarbagecollection_additionalfieldprovider.php',
index 73e1edb..61b0a8f 100755 (executable)
@@ -28,1592 +28,6 @@ require_once (t3lib_extMgm::extPath('scheduler') . 'interfaces/interface.tx_sche
 $LANG->includeLLFile('EXT:scheduler/mod1/locallang.xml');
 $BE_USER->modAccess($MCONF, 1); // This checks permissions and exits if the users has no permission for entry.
 
-/**
- * Module 'TYPO3 Scheduler administration module' for the 'scheduler' extension.
- *
- * @author             François Suter <francois@typo3.org>
- * @author             Christian Jul Jensen <julle@typo3.org>
- * @author             Ingo Renner <ingo@typo3.org>
- * @package            TYPO3
- * @subpackage tx_scheduler
- */
-class tx_scheduler_Module extends t3lib_SCbase {
-
-       /**
-        * Back path to typo3 main dir
-        *
-        * @var string          $backPath
-        */
-       public $backPath;
-
-       /**
-        * Array containing submitted data when editing or adding a task
-        *
-        * @var array           $submittedData
-        */
-       protected $submittedData = array();
-
-       /**
-        * Array containing all messages issued by the application logic
-        * Contains the error's severity and the message itself
-        *
-        * @var array   $messages
-        */
-       protected $messages = array();
-
-       /**
-        * @var string  Key of the CSH file
-        */
-       protected $cshKey;
-
-       /**
-        *
-        * @var tx_scheduler    Local scheduler instance
-        */
-       protected $scheduler;
-
-       /**
-        * Constructor
-        *
-        * @return      void
-        */
-       public function __construct() {
-               $this->backPath = $GLOBALS['BACK_PATH'];
-                       // Set key for CSH
-               $this->cshKey = '_MOD_' . $GLOBALS['MCONF']['name'];
-       }
-
-       /**
-        * Initializes the backend module
-        *
-        * @return      void
-        */
-       public function init() {
-               parent::init();
-
-                       // Initialize document
-               $this->doc = t3lib_div::makeInstance('template');
-               $this->doc->setModuleTemplate(t3lib_extMgm::extPath('scheduler') . 'mod1/mod_template.html');
-               $this->doc->getPageRenderer()->addCssFile(t3lib_extMgm::extRelPath('scheduler') . 'res/tx_scheduler_be.css');
-               $this->doc->backPath = $this->backPath;
-               $this->doc->bodyTagId = 'typo3-mod-php';
-               $this->doc->bodyTagAdditions = 'class="tx_scheduler_mod1"';
-
-                       // Create scheduler instance
-               $this->scheduler = t3lib_div::makeInstance('tx_scheduler');
-       }
-
-       /**
-        * Adds items to the ->MOD_MENU array. Used for the function menu selector.
-        *
-        * @return      void
-        */
-       public function menuConfig() {
-               $this->MOD_MENU = array(
-                       'function' => array(
-                               'scheduler' => $GLOBALS['LANG']->getLL('function.scheduler'),
-                               'check'     => $GLOBALS['LANG']->getLL('function.check'),
-                               'info'      => $GLOBALS['LANG']->getLL('function.info'),
-                       )
-               );
-
-               parent::menuConfig();
-       }
-
-       /**
-        * Main function of the module. Write the content to $this->content
-        *
-        * @return      void
-        */
-       public function main() {
-                       // Access check!
-                       // The page will show only if user has admin rights
-               if ($GLOBALS['BE_USER']->user['admin']) {
-
-                               // Set the form
-                       $this->doc->form = '<form name="tx_scheduler_form" id="tx_scheduler_form" method="post" action="">';
-
-                               // JavaScript for main function menu
-                       $this->doc->JScode = '
-                               <script language="javascript" type="text/javascript">
-                                       script_ended = 0;
-                                       function jumpToUrl(URL) {
-                                               document.location = URL;
-                                       }
-                               </script>
-                       ';
-
-                               // Prepare main content
-                       $this->content  = $this->doc->header(
-                               $GLOBALS['LANG']->getLL('function.' . $this->MOD_SETTINGS['function'])
-                       );
-                       $this->content .= $this->doc->spacer(5);
-                       $this->content .= $this->getModuleContent();
-               } else {
-                               // If no access, only display the module's title
-                       $this->content  = $this->doc->header($GLOBALS['LANG']->getLL('title'));
-                       $this->content .= $this->doc->spacer(5);
-               }
-
-                       // Place content inside template
-
-               $content = $this->doc->moduleBody(
-                       array(),
-                       $this->getDocHeaderButtons(),
-                       $this->getTemplateMarkers()
-               );
-
-                       // Renders the module page
-               $this->content = $this->doc->render(
-                       $GLOBALS['LANG']->getLL('title'),
-                       $content
-               );
-       }
-
-       /**
-        * Generate the module's content
-        *
-        * @return      string  HTML of the module's main content
-        */
-       protected function getModuleContent() {
-               $content = '';
-               $sectionTitle = '';
-
-                       // Get submitted data
-               $this->submittedData = t3lib_div::_GPmerged('tx_scheduler');
-
-                       // If a save command was submitted, handle saving now
-               if ($this->CMD == 'save') {
-                       $previousCMD = t3lib_div::_GP('previousCMD');
-                               // First check the submitted data
-                       $result = $this->preprocessData();
-
-                               // If result is ok, proceed with saving
-                       if ($result) {
-                               $this->saveTask();
-                                       // Unset command, so that default screen gets displayed
-                               unset($this->CMD);
-
-                               // Errors occurred
-                               // Go back to previous step
-                       } else {
-                               $this->CMD = $previousCMD;
-                       }
-               }
-
-                       // Handle chosen action
-               switch((string)$this->MOD_SETTINGS['function']) {
-                       case 'scheduler':
-                                       // Scheduler's main screen
-                               $content .= $this->executeTasks();
-
-                                       // Execute chosen action
-                               switch ($this->CMD) {
-                                       case 'add':
-                                       case 'edit':
-                                               try {
-                                                               // Try adding or editing
-                                                       $content .= $this->editTask();
-                                                       $sectionTitle = $GLOBALS['LANG']->getLL('action.' . $this->CMD);
-                                               } catch (Exception $e) {
-                                                               // An exception may happen when the task to
-                                                               // edit could not be found. In this case revert
-                                                               // to displaying the list of tasks
-                                                               // It can also happend when attempting to edit a running task
-                                                       $content .= $this->listTasks();
-                                               }
-                                               break;
-                                       case 'delete':
-                                               $this->deleteTask();
-                                               $content .= $this->listTasks();
-                                               break;
-                                       case 'stop':
-                                               $this->stopTask();
-                                               $content .= $this->listTasks();
-                                               break;
-                                       case 'list':
-                                       default:
-                                               $content .= $this->listTasks();
-                                               break;
-                               }
-                               break;
-                       case 'check':
-                                       // Setup check screen
-                                       // TODO: move check to the report module
-                               $content .= $this->displayCheckScreen();
-                               break;
-                       case 'info':
-                                       // Information screen
-                               $content .= $this->displayInfoScreen();
-                               break;
-               }
-
-                       // Wrap the content in a section
-               return $this->doc->section($sectionTitle, '<div class="tx_scheduler_mod1">' . $content . '</div>', 0, 1);
-       }
-
-       /**
-        * This method actually prints out the module's HTML content
-        *
-        * @return      void
-        */
-       public function render() {
-               echo $this->content;
-       }
-
-       /**
-        * This method checks the status of the '_cli_scheduler' user
-        * It will differentiate between a non-existing user and an existing,
-        * but disabled user (as per enable fields)
-        *
-        * @return      integer         -1      if user doesn't exist
-        *                                               0      if user exists, but is disabled
-        *                                               1      if user exists and is not disabled
-        */
-       protected function checkSchedulerUser() {
-               $schedulerUserStatus = -1;
-                       // Assemble base WHERE clause
-               $where = 'username = \'_cli_scheduler\' AND admin = 0' . t3lib_BEfunc::deleteClause('be_users');
-                       // Check if user exists at all
-               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-                       '1',
-                       'be_users',
-                       $where
-               );
-               if ($GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                       $schedulerUserStatus = 0;
-                               // Check if user exists and is enabled
-                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
-                               '1',
-                               'be_users',
-                               $where . t3lib_BEfunc::BEenableFields('be_users')
-                       );
-                       if ($GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                               $schedulerUserStatus = 1;
-                       }
-               }
-               $GLOBALS['TYPO3_DB']->sql_free_result($res);
-
-               return $schedulerUserStatus;
-       }
-
-       /**
-        * This method creates the "cli_scheduler" BE user if it doesn't exist
-        *
-        * @return      void
-        */
-       protected function createSchedulerUser() {
-                       // Check _cli_scheduler user status
-               $checkUser = $this->checkSchedulerUser();
-                       // Prepare default message
-               $message = $GLOBALS['LANG']->getLL('msg.userExists');
-               $severity = t3lib_FlashMessage::WARNING;
-                       // If the user does not exist, try creating it
-               if ($checkUser == -1) {
-                               // Prepare necessary data for _cli_scheduler user creation
-                       $password = md5(uniqid('scheduler', true));
-                       $data = array('be_users' => array('NEW' => array('username' => '_cli_scheduler', 'password' => $password, 'pid' => 0)));
-                               /**
-                                * Create an instance of TCEmain and execute user creation
-                                *
-                                * @var t3lib_TCEmain
-                                */
-                       $tcemain = t3lib_div::makeInstance('t3lib_TCEmain');
-                       $tcemain->stripslashes_values = 0;
-                       $tcemain->start($data, array());
-                       $tcemain->process_datamap();
-                               // Check if a new uid was indeed generated (i.e. a new record was created)
-                               // (counting TCEmain errors doesn't work as some failures don't report errors)
-                       $numberOfNewIDs = count($tcemain->substNEWwithIDs);
-                       if ($numberOfNewIDs == 1) {
-                               $message = $GLOBALS['LANG']->getLL('msg.userCreated');
-                               $severity = t3lib_FlashMessage::OK;
-                       } else {
-                               $message = $GLOBALS['LANG']->getLL('msg.userNotCreated');
-                               $severity = t3lib_FlashMessage::ERROR;
-                       }
-               }
-               $this->addMessage($message, $severity);
-       }
-
-       /**
-        * This method displays the result of a number of checks
-        * on whether the Scheduler is ready to run or running properly
-        *
-        * @return      string  further information
-        */
-       protected function displayCheckScreen() {
-               $message = '';
-               $severity = t3lib_FlashMessage::OK;
-
-                       // First, check if cli_sceduler user creation was requested
-               if ($this->CMD == 'user') {
-                       $this->createSchedulerUser();
-               }
-
-                       // Start generating the content
-               $content = $GLOBALS['LANG']->getLL('msg.schedulerSetupCheck');
-
-                       // Display information about last automated run, as stored in the system registry
-                       /**
-                        * @var t3lib_Registry
-                        */
-               $registry = t3lib_div::makeInstance('t3lib_Registry');
-               $lastRun = $registry->get('tx_scheduler', 'lastRun');
-               if (!is_array($lastRun)) {
-                       $message = $GLOBALS['LANG']->getLL('msg.noLastRun');
-                       $severity = t3lib_FlashMessage::WARNING;
-               } else {
-                       if (empty($lastRun['end']) || empty($lastRun['start']) || empty($lastRun['type'])) {
-                               $message = $GLOBALS['LANG']->getLL('msg.incompleteLastRun');
-                               $severity = t3lib_FlashMessage::WARNING;
-                       } else {
-                               $startDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $lastRun['start']);
-                               $startTime = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $lastRun['start']);
-                               $endDate = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $lastRun['end']);
-                               $endTime = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $lastRun['end']);
-                               $label = 'automatically';
-                               if ($lastRun['type'] == 'manual') {
-                                       $label = 'manually';
-                               }
-                               $type = $GLOBALS['LANG']->getLL('label.' . $label);
-                               $message = sprintf($GLOBALS['LANG']->getLL('msg.lastRun'), $type, $startDate, $startTime, $endDate, $endTime);
-                               $severity = t3lib_FlashMessage::INFO;
-                       }
-               }
-               $flashMessage = t3lib_div::makeInstance(
-                       't3lib_FlashMessage',
-                       $message,
-                       '',
-                       $severity
-               );
-               $content .= '<div class="info-block">';
-               $content .= '<h3>' . $GLOBALS['LANG']->getLL('hdg.lastRun') . '</h3>';
-               $content .= $flashMessage->render();
-               $content .= '</div>';
-
-                       // Check CLI user
-               $content .= '<div class="info-block">';
-               $content .= '<h3>' . $GLOBALS['LANG']->getLL('hdg.schedulerUser') . '</h3>';
-               $content .= '<p>' . $GLOBALS['LANG']->getLL('msg.schedulerUser') . '</p>';
-
-               $checkUser = $this->checkSchedulerUser();
-               if ($checkUser == -1) {
-                       $link = $GLOBALS['MCONF']['_'] . '&SET[function]=check&CMD=user';
-                       $message = sprintf($GLOBALS['LANG']->getLL('msg.schedulerUserMissing'), htmlspecialchars($link));
-                       $severity = t3lib_FlashMessage::ERROR;
-               } elseif ($checkUser == 0) {
-                       $message = $GLOBALS['LANG']->getLL('msg.schedulerUserFoundButDisabled');
-                       $severity = t3lib_FlashMessage::WARNING;
-               } else {
-                       $message = $GLOBALS['LANG']->getLL('msg.schedulerUserFound');
-                       $severity = t3lib_FlashMessage::OK;
-               }
-               $flashMessage = t3lib_div::makeInstance(
-                       't3lib_FlashMessage',
-                       $message,
-                       '',
-                       $severity
-               );
-               $content .= $flashMessage->render() . '</div>';
-
-                       // Check if CLI script is executable or not
-               $script = PATH_typo3 . 'cli_dispatch.phpsh';
-               $isExecutable = FALSE;
-                       // Skip this check if running Windows, as rights do not work the same way on this platform
-                       // (i.e. the script will always appear as *not* executable)
-               if (TYPO3_OS === 'WIN') {
-                       $isExecutable = TRUE;
-               } else {
-                       $isExecutable = is_executable($script);
-               }
-               $content .= '<div class="info-block">';
-               $content .= '<h3>' . $GLOBALS['LANG']->getLL('hdg.cliScript') . '</h3>';
-               $content .= '<p>' . sprintf($GLOBALS['LANG']->getLL('msg.cliScript'), $script) . '</p>';
-
-               if ($isExecutable) {
-                       $message = $GLOBALS['LANG']->getLL('msg.cliScriptExecutable');
-                       $severity = t3lib_FlashMessage::OK;
-               } else {
-                       $message = $GLOBALS['LANG']->getLL('msg.cliScriptNotExecutable');
-                       $severity = t3lib_FlashMessage::ERROR;
-               }
-               $flashMessage = t3lib_div::makeInstance(
-                       't3lib_FlashMessage',
-                       $message,
-                       '',
-                       $severity
-               );
-               $content .= $flashMessage->render() . '</div>';
-
-               return $content;
-       }
-
-       /**
-        * This method gathers information about all available task classes and displays it
-        *
-        * @return      string  HTML content to display
-        */
-       protected function displayInfoScreen() {
-               $content = '';
-               $registeredClasses = self::getRegisteredClasses();
-
-                       // No classes available, display information message
-               if (count($registeredClasses) == 0) {
-                               /** @var t3lib_FlashMessage $flashMessage */
-                       $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage',
-                               $GLOBALS['LANG']->getLL('msg.noTasksDefined'),
-                               '',
-                               t3lib_FlashMessage::INFO
-                       );
-                       $content .= $flashMessage->render();
-
-                       // Display the list of all available classes
-               } else {
-                               // Initialise table layout
-                       $tableLayout = array (
-                               'table' => array ('<table border="0" cellspacing="1" cellpadding="2" class="typo3-dblist">', '</table>'),
-                               '0' => array (
-                                       'tr' => array('<tr class="t3-row-header" valign="top">', '</tr>'),
-                                       'defCol' => array('<td>', '</td>')
-                               ),
-                               'defRow' => array (
-                                       'tr' => array('<tr class="db_list_normal">', '</tr>'),
-                                       'defCol' => array('<td>', '</td>')
-                               )
-                       );
-                       $table = array();
-                       $tr = 0;
-
-                               // Header row
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.name');
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.extension');
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.description');
-                       $table[$tr][] = '';
-                       $tr++;
-
-                               // Display information about each service
-                       foreach ($registeredClasses as $class => $classInfo) {
-                               $table[$tr][] = $classInfo['title'];
-                               $table[$tr][] = $classInfo['extension'];
-                               $table[$tr][] = $classInfo['description'];
-                               $link = $GLOBALS['MCONF']['_'] . '&SET[function]=list&CMD=add&tx_scheduler[class]=' . $class;
-                               $table[$tr][] = '<a href="' . htmlspecialchars($link) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:new', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-document-new') . '</a>';
-                               $tr++;
-                       }
-
-                               // Render the table and return it
-                       $content  = '<div>' . $GLOBALS['LANG']->getLL('msg.infoScreenIntro') . '</div>';
-                       $content .= $this->doc->spacer(5);
-                       $content .= $this->doc->table($table, $tableLayout);
-               }
-
-               return $content;
-       }
-
-       /**
-        * Display the current server's time along with a help text about server time
-        * usage in the Scheduler
-        *
-        * @return      string  HTML to display
-        */
-       protected function displayServerTime() {
-                       // Get the current time, formatted
-               $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] . ' T (e';
-               $now = date($dateFormat) . ', GMT ' . date('P') . ')';
-                       // Display the help text
-               $serverTime  = '<h4>' . $GLOBALS['LANG']->getLL('label.serverTime') . '</h4>';
-               $serverTime .= '<p>' . $GLOBALS['LANG']->getLL('msg.serverTimeHelp') . '</p>';
-               $serverTime .= '<p>' . sprintf($GLOBALS['LANG']->getLL('msg.serverTime'), $now) . '</p>';
-               return $serverTime;
-       }
-
-       /**
-        * Delete a task from the execution queue
-        *
-        * @return      void
-        */
-       protected function deleteTask() {
-               try {
-                               // Try to fetch the task and delete it
-                               /**
-                                * @var tx_scheduler_Task
-                                */
-                       $task = $this->scheduler->fetchTask($this->submittedData['uid']);
-                               // If the task is currently running, it may not be deleted
-                       if ($task->isExecutionRunning()) {
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.maynotDeleteRunningTask'), t3lib_FlashMessage::ERROR);
-                       } else {
-                               if ($this->scheduler->removeTask($task)) {
-                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteSuccess'));
-                               } else {
-                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteError'), t3lib_FlashMessage::ERROR);
-                               }
-                       }
-               } catch (UnexpectedValueException $e) {
-                               // The task could not be unserialized properly, simply delete the database record
-                       $result = $GLOBALS['TYPO3_DB']->exec_DELETEquery('tx_scheduler_task', 'uid = ' . intval($this->submittedData['uid']));
-                       if ($result) {
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteSuccess'));
-                       } else {
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.deleteError'), t3lib_FlashMessage::ERROR);
-                       }
-               } catch (OutOfBoundsException $e) {
-                               // The task was not found, for some reason
-                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR);
-               }
-       }
-
-       /**
-        * Clears the registered running executions from the task
-        * Note that this doesn't actually stop the running script. It just unmarks
-        * all executions.
-        * TODO: find a way to really kill the running task
-        *
-        * @return      void
-        */
-       protected function stopTask() {
-               try {
-                               // Try to fetch the task and stop it
-                               /**
-                                * @var tx_scheduler_Task
-                                */
-                       $task = $this->scheduler->fetchTask($this->submittedData['uid']);
-                       if ($task->isExecutionRunning()) {
-                               // If the task is indeed currently running, clear marked executions
-
-                               $result = $task->unmarkAllExecutions();
-                               if ($result) {
-                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.stopSuccess'));
-                               } else {
-                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.stopError'), t3lib_FlashMessage::ERROR);
-                               }
-                       } else {
-                               // The task is not running, nothing to unmark
-
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.maynotStopNonRunningTask'), t3lib_FlashMessage::WARNING);
-                       }
-               } catch (Exception $e) {
-                               // The task was not found, for some reason
-                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR);
-               }
-       }
-
-       /**
-        * Return a form to add a new task or edit an existing one
-        *
-        * @return      string  HTML form to add or edit a task
-        */
-       protected function editTask() {
-               $registeredClasses = self::getRegisteredClasses();
-               $content = '';
-               $taskInfo = array();
-               $task = NULL;
-               $process = 'edit';
-
-               if ($this->submittedData['uid'] > 0) {
-                               // If editing, retrieve data for existing task
-                       try {
-                               $taskRecord = $this->scheduler->fetchTaskRecord($this->submittedData['uid']);
-                                       // If there's a registered execution, the task should not be edited
-                               if (!empty($taskRecord['serialized_executions'])) {
-                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.maynotEditRunningTask'), t3lib_FlashMessage::ERROR);
-                                       throw new LogicException('Runnings tasks cannot not be edited', 1251232849);
-                               }
-                                       // Get the task object
-                               $task = unserialize($taskRecord['serialized_task_object']);
-
-                                       // Set some task information
-                               $class = $taskRecord['classname'];
-                               $taskInfo['disable'] = $taskRecord['disable'];
-
-                                       // Check that the task object is valid
-                               if ($this->scheduler->isValidTaskObject($task)) {
-                                       // The task object is valid, process with fetching current data
-
-                                       $taskInfo['class'] = $class;
-
-                                               // Get execution information
-                                       $taskInfo['start']    = $task->getExecution()->getStart();
-                                       $taskInfo['end']      = $task->getExecution()->getEnd();
-                                       $taskInfo['interval'] = $task->getExecution()->getInterval();
-                                       $taskInfo['croncmd']  = $task->getExecution()->getCronCmd();
-                                       $taskInfo['multiple'] = $task->getExecution()->getMultiple();
-
-                                       if (!empty($taskInfo['interval']) || !empty($taskInfo['croncmd'])) {
-                                                       // Guess task type from the existing information
-                                                       // If an interval or a cron command is defined, it's a recurring task
-
-                                                       // FIXME remove magic numbers for the type, use class constants instead
-                                               $taskInfo['type']      = 2;
-                                               $taskInfo['frequency'] = (empty($taskInfo['interval'])) ? $taskInfo['croncmd'] : $taskInfo['interval'];
-                                       } else {
-                                                       // It's not a recurring task
-                                                       // Make sure interval and cron command are both empty
-                                               $taskInfo['type']      = 1;
-                                               $taskInfo['frequency'] = '';
-                                               $taskInfo['end']       = 0;
-                                       }
-                               } else {
-                                       // The task object is not valid
-
-                                               // Issue error message
-                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.invalidTaskClassEdit'), $class), t3lib_FlashMessage::ERROR);
-                                               // Initialize empty values
-                                       $taskInfo['start']     = 0;
-                                       $taskInfo['end']       = 0;
-                                       $taskInfo['frequency'] = '';
-                                       $taskInfo['multiple']  = false;
-                                       $taskInfo['type']      = 1;
-                               }
-                       } catch (OutOfBoundsException $e) {
-                                       // Add a message and continue throwing the exception
-                               $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR);
-                               throw $e;
-                       }
-               } else {
-                               // If adding a new object, set some default values
-                       $taskInfo['class'] = key($registeredClasses);
-                       $taskInfo['type'] = 2;
-                       $taskInfo['start'] = $GLOBALS['EXEC_TIME'];
-                       $taskInfo['end'] = '';
-                       $taskInfo['frequency'] = '';
-                       $taskInfo['multiple'] = 0;
-                       $process = 'add';
-               }
-
-               if (count($this->submittedData) > 0) {
-                               // If some data was already submitted, use it to override
-                               // existing data
-                       $taskInfo = t3lib_div::array_merge_recursive_overrule($taskInfo, $this->submittedData);
-               }
-
-                       // Get the extra fields to display for each task that needs some
-               $allAdditionalFields = array();
-               if ($process == 'add') {
-                       foreach ($registeredClasses as $class => $registrationInfo) {
-                               if (!empty($registrationInfo['provider'])) {
-                                       $providerObject = t3lib_div::getUserObj($registrationInfo['provider']);
-                                       if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
-                                               $additionalFields = $providerObject->getAdditionalFields($taskInfo, NULL, $this);
-                                               $allAdditionalFields = array_merge($allAdditionalFields, array($class => $additionalFields));
-                                       }
-                               }
-                       }
-
-                       // In case of edit, get only the extra fields for the current task class
-               } else {
-                       if (!empty($registeredClasses[$taskInfo['class']]['provider'])) {
-                               $providerObject = t3lib_div::getUserObj($registeredClasses[$taskInfo['class']]['provider']);
-                               if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
-                                       $allAdditionalFields[$taskInfo['class']] = $providerObject->getAdditionalFields($taskInfo, $task, $this);
-                               }
-                       }
-               }
-
-                       // Load necessary JavaScript
-                       /** @var $pageRenderer t3lib_PageRenderer */
-               $pageRenderer = $this->doc->getPageRenderer();
-               $pageRenderer->loadExtJS();
-               $pageRenderer->addJsFile(t3lib_extMgm::extRelPath('scheduler') . 'res/tx_scheduler_be.js');
-               $pageRenderer->addJsFile($this->backPath . '../t3lib/js/extjs/tceforms.js');
-
-                       // Define settings for Date Picker
-               $typo3Settings = array(
-                       'datePickerUSmode' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? 1 : 0,
-                       'dateFormat'       => array('j-n-Y', 'G:i j-n-Y'),
-                       'dateFormatUS'     => array('n-j-Y', 'G:i n-j-Y'),
-               );
-               $pageRenderer->addInlineSettingArray('', $typo3Settings);
-
-                       // Define table layout for add/edit form
-               $tableLayout = array (
-                       'table' => array ('<table border="0" cellspacing="0" cellpadding="0" id="edit_form" class="typo3-usersettings">', '</table>'),
-               );
-
-                       // Define a style for hiding
-                       // Some fields will be hidden when the task is not recurring
-               $style = '';
-               if ($taskInfo['type'] == 1) {
-                       $style = ' style="display: none"';
-               }
-
-                       // Start rendering the add/edit form
-               $content .= '<input type="hidden" name="tx_scheduler[uid]" value="' . $this->submittedData['uid'] . '" />';
-               $content .= '<input type="hidden" name="previousCMD" value="' . $this->CMD . '" />';
-               $content .= '<input type="hidden" name="CMD" value="save" />';
-
-               $table = array();
-               $tr = 0;
-               $defaultCell = array('<td class="td-input">', '</td>');
-
-                       // Disable checkbox
-               $label = '<label for="task_disable">' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:disable') . '</label>';
-               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_disable', $label);
-               $table[$tr][] =
-                       '<input type="hidden"   name="tx_scheduler[disable]" value="0" />
-                        <input type="checkbox" name="tx_scheduler[disable]" value="1" id="task_disable"' . ($taskInfo['disable'] == 1 ? ' checked="checked"' : '') . ' />';
-               $tableLayout[$tr] = array (
-                       'tr'     => array('<tr id="task_disable_row">', '</tr>'),
-                       'defCol' => $defaultCell,
-                       '0'      => array('<td class="td-label">', '</td>')
-               );
-               $tr++;
-
-                       // Task class selector
-               $label = '<label for="task_class">' . $GLOBALS['LANG']->getLL('label.class') . '</label>';
-               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_class', $label);
-                       // On editing, don't allow changing of the task class, unless it was not valid
-               if ($this->submittedData['uid'] > 0 && !empty($taskInfo['class'])) {
-                       $cell = $registeredClasses[$taskInfo['class']]['title'] . ' (' . $registeredClasses[$taskInfo['class']]['extension'] . ')';
-                       $cell .= '<input type="hidden" name="tx_scheduler[class]" id="task_class" value="' . $taskInfo['class'] . '" />';
-               } else {
-                       $cell = '<select name="tx_scheduler[class]" id="task_class" class="wide" onchange="actOnChangedTaskClass(this)">';
-                               // Loop on all registered classes to display a selector
-                       foreach ($registeredClasses as $class => $classInfo) {
-                               $selected = ($class == $taskInfo['class']) ? ' selected="selected"' : '';
-                               $cell .= '<option value="' . $class . '"' . $selected . '>' . $classInfo['title'] . ' (' . $classInfo['extension'] . ')' . '</option>';
-                       }
-                       $cell .= '</select>';
-               }
-               $table[$tr][] = $cell;
-                       // Make sure each row has a unique id, for manipulation with JS
-               $tableLayout[$tr] = array (
-                       'tr'     => array('<tr id="task_class_row">', '</tr>'),
-                       'defCol' => $defaultCell,
-                       '0'      => array('<td class="td-label">', '</td>')
-               );
-               $tr++;
-
-                       // Task type selector
-               $label = '<label for="task_type">' . $GLOBALS['LANG']->getLL('label.type') . '</label>';
-               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_type', $label);
-               $table[$tr][] =
-                       '<select name="tx_scheduler[type]" id="task_type" onchange="actOnChangedTaskType(this)">' .
-                               '<option value="1"' . ($taskInfo['type'] == 1 ? ' selected="selected"' : '') . '>' . $GLOBALS['LANG']->getLL('label.type.single') . '</option>' .
-                               '<option value="2"' . ($taskInfo['type'] == 2 ? ' selected="selected"' : '') . '>' . $GLOBALS['LANG']->getLL('label.type.recurring') . '</option>' .
-                       '</select>';
-               $tableLayout[$tr] = array (
-                       'tr'     => array('<tr id="task_type_row">', '</tr>'),
-                       'defCol' => $defaultCell,
-                       '0'      => array('<td class="td-label">', '</td>'),
-               );
-               $tr++;
-
-                       // Start date/time field
-                       // NOTE: datetime fields need a special id naming scheme
-               $label = '<label for="tceforms-datetimefield-task_start">' . $GLOBALS['LANG']->getLL('label.start') . '</label>';
-               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_start', $label);
-               $table[$tr][] = '<input name="tx_scheduler[start]" type="text" id="tceforms-datetimefield-task_start" value="' . ((empty($taskInfo['start'])) ? '' : strftime('%H:%M %d-%m-%Y', $taskInfo['start'])) . '" />' .
-                       t3lib_iconWorks::getSpriteIcon(
-                               'actions-edit-pick-date',
-                               array(
-                                       'style' => 'cursor:pointer;',
-                                       'id' => 'picker-tceforms-datetimefield-task_start'
-                               )
-                       );
-               $tableLayout[$tr] = array (
-                       'tr' => array('<tr id="task_start_row">', '</tr>'),
-                       'defCol' => $defaultCell,
-                       '0'      => array('<td class="td-label">', '</td>')
-               );
-               $tr++;
-
-                       // End date/time field
-                       // NOTE: datetime fields need a special id naming scheme
-               $label = '<label for="tceforms-datetimefield-task_end">' . $GLOBALS['LANG']->getLL('label.end') . '</label>';
-               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_end', $label);
-               $table[$tr][] = '<input name="tx_scheduler[end]" type="text" id="tceforms-datetimefield-task_end" value="' . ((empty($taskInfo['end'])) ? '' : strftime('%H:%M %d-%m-%Y', $taskInfo['end'])) . '" />' .
-                       t3lib_iconWorks::getSpriteIcon(
-                               'actions-edit-pick-date',
-                               array(
-                                       'style' => 'cursor:pointer;',
-                                       'id' => 'picker-tceforms-datetimefield-task_end'
-                               )
-                       );
-               $tableLayout[$tr] = array (
-                       'tr'     => array('<tr id="task_end_row"' . $style . '>', '</tr>'),
-                       'defCol' => $defaultCell,
-                       '0'      => array('<td class="td-label">', '</td>'),
-               );
-               $tr++;
-
-                       // Frequency input field
-               $label = '<label for="task_frequency">' . $GLOBALS['LANG']->getLL('label.frequency.long') . '</label>';
-               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_frequency', $label);
-               $cell = '<input type="text" name="tx_scheduler[frequency]" id="task_frequency" value="' . $taskInfo['frequency'] . '" />';
-               $table[$tr][] = $cell;
-               $tableLayout[$tr] = array (
-                       'tr'     => array('<tr id="task_frequency_row"' . $style . '>', '</tr>'),
-                       'defCol' => $defaultCell,
-                       '0'      => array('<td class="td-label">', '</td>'),
-               );
-               $tr++;
-
-                       // Multiple execution selector
-               $label = '<label for="task_multiple">' . $GLOBALS['LANG']->getLL('label.parallel.long') . '</label>';
-               $table[$tr][] = t3lib_BEfunc::wrapInHelp($this->cshKey, 'task_multiple', $label);
-               $table[$tr][] =
-                       '<input type="hidden"   name="tx_scheduler[multiple]" value="0" />
-                        <input type="checkbox" name="tx_scheduler[multiple]" value="1" id="task_multiple"' . ($taskInfo['multiple'] == 1 ? ' checked="checked"' : '') . ' />';
-               $tableLayout[$tr] = array (
-                       'tr'     => array('<tr id="task_multiple_row"' . $style . '>', '</tr>'),
-                       'defCol' => $defaultCell,
-                       '0'      => array('<td class="td-label">', '</td>')
-               );
-               $tr++;
-
-                       // Display additional fields
-               foreach ($allAdditionalFields as $class => $fields) {
-                       if ($class == $taskInfo['class']) {
-                               $additionalFieldsStyle = '';
-                       } else {
-                               $additionalFieldsStyle = ' style="display: none"';
-                       }
-
-                               // Add each field to the display, if there are indeed any
-                       if (isset($fields) && is_array($fields)) {
-                               foreach ($fields as $fieldID => $fieldInfo) {
-                                       $label = '<label for="' . $fieldID . '">' . $GLOBALS['LANG']->sL($fieldInfo['label']) . '</label>';
-                                       $table[$tr][] = t3lib_BEfunc::wrapInHelp($fieldInfo['cshKey'], $fieldInfo['cshLabel'], $label);
-                                       $table[$tr][] = $fieldInfo['code'];
-                                       $tableLayout[$tr] = array (
-                                               'tr'     => array('<tr id="' . $fieldID . '_row"' . $additionalFieldsStyle .' class="extraFields extra_fields_' . $class . '">', '</tr>'),
-                                               'defCol' => $defaultCell,
-                                               '0'      => array('<td class="td-label">', '</td>')
-                                       );
-                                       $tr++;
-                               }
-                       }
-               }
-
-                       // Render the add/edit task form
-               $content .= '<div style="float: left;"><div class="typo3-dyntabmenu-divs">';
-               $content .= $this->doc->table($table, $tableLayout);
-               $content .= '</div></div>';
-
-               $content .= '<div style="padding-top: 20px; clear: both;"></div><div><input type="submit" name="save" class="button" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:save', TRUE) . '" /> '
-                       . '<input type="button" name="cancel" class="button" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:cancel', TRUE) . '" onclick="document.location=\'' . $GLOBALS['MCONF']['_'] . '\'" /></div>';
-
-                       // Display information about server time usage
-               $content .= $this->displayServerTime();
-
-               return $content;
-       }
-
-       /**
-        * Execute all selected tasks
-        *
-        * @return      void
-        */
-       protected function executeTasks() {
-                       // Continue if some elements have been chosen for execution
-               if (isset($this->submittedData['execute']) && count($this->submittedData['execute']) > 0) {
-
-                               // Get list of registered classes
-                       $registeredClasses = self::getRegisteredClasses();
-
-                               // Loop on all selected tasks
-                       foreach ($this->submittedData['execute'] as $uid) {
-
-                               try {
-                                               // Try fetching the task
-                                       $task = $this->scheduler->fetchTask($uid);
-                                       $class = get_class($task);
-                                       $name = $registeredClasses[$class]['title']. ' (' . $registeredClasses[$class]['extension'] . ')';
-                                               // Now try to execute it and report on outcome
-                                       try {
-                                               $result = $this->scheduler->executeTask($task);
-                                               if ($result) {
-                                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.executed'), $name));
-                                               } else {
-                                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.notExecuted'), $name), t3lib_FlashMessage::ERROR);
-                                               }
-                                       }
-                                       catch (Exception $e) {
-                                                       // An exception was thrown, display its message as an error
-                                               $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.executionFailed'), $name, $e->getMessage()), t3lib_FlashMessage::ERROR);
-                                       }
-                               }
-                                       // The task was not found, for some reason
-                               catch (OutOfBoundsException $e) {
-                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $uid), t3lib_FlashMessage::ERROR);
-                               }
-                                       // The task object was not valid
-                               catch (UnexpectedValueException $e) {
-                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.executionFailed'), $name, $e->getMessage()), t3lib_FlashMessage::ERROR);
-                               }
-                       }
-                               // Record the run in the system registry
-                       $this->scheduler->recordLastRun('manual');
-                               // Make sure to switch to list view after execution
-                       $this->CMD = 'list';
-               }
-       }
-
-       /**
-        * Assemble display of list of scheduled tasks
-        *
-        * @return      string                  table of waiting schedulings
-        */
-       protected function listTasks() {
-                       // Define display format for dates
-               $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
-               $content = '';
-
-                       // Get list of registered classes
-               $registeredClasses = self::getRegisteredClasses();
-
-                       // Get all registered tasks
-               $query = array(
-                       'SELECT'  => '*',
-                       'FROM'    => 'tx_scheduler_task',
-                       'WHERE'   => '1=1',
-                       'ORDERBY' => 'nextexecution'
-               );
-
-               $res = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($query);
-               $numRows = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
-                       // No tasks defined, display information message
-               if ($numRows == 0) {
-                               /** @var t3lib_FlashMessage $flashMessage */
-                       $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage',
-                               $GLOBALS['LANG']->getLL('msg.noTasks'),
-                               '',
-                               t3lib_FlashMessage::INFO
-                       );
-                       $content .= $flashMessage->render();
-               } else {
-                               // Load ExtJS framework and specific JS library
-                               /** @var $pageRenderer t3lib_PageRenderer */
-                       $pageRenderer = $this->doc->getPageRenderer();
-                       $pageRenderer->loadExtJS();
-                       $pageRenderer->addJsFile(t3lib_extMgm::extRelPath('scheduler') . 'res/tx_scheduler_be.js');
-
-                               // Initialise table layout
-                       $tableLayout = array(
-                               'table' => array(
-                                       '<table border="0" cellspacing="1" cellpadding="2" class="typo3-dblist">', '</table>'
-                               ),
-                               '0'     => array(
-                                       'tr'     => array('<tr class="t3-row-header">', '</tr>'),
-                                       'defCol' => array('<td>', '</td>'),
-                                       '1'      => array('<td style="width: 36px;">', '</td>'),
-                                       '3'      => array('<td colspan="2">', '</td>'),
-                               ),
-                               'defRow' => array(
-                                       'tr'     => array('<tr class="db_list_normal">', '</tr>'),
-                                       'defCol' => array('<td>', '</td>'),
-                                       '1'      => array('<td class="right">', '</td>'),
-                                       '2'      => array('<td class="right">', '</td>'),
-                               )
-                       );
-                       $disabledTaskRow = array (
-                               'tr'     => array('<tr class="db_list_normal disabled">', '</tr>'),
-                               'defCol' => array('<td>', '</td>'),
-                               '1'      => array('<td class="right">', '</td>'),
-                               '2'      => array('<td class="right">', '</td>'),
-                       );
-                       $rowWithSpan = array (
-                               'tr'     => array('<tr class="db_list_normal">', '</tr>'),
-                               'defCol' => array('<td>', '</td>'),
-                               '1'      => array('<td class="right">', '</td>'),
-                               '2'      => array('<td class="right">', '</td>'),
-                               '3'      => array('<td colspan="6">', '</td>'),
-                       );
-                       $table = array();
-                       $tr = 0;
-
-                               // Header row
-                       $table[$tr][] = '<a href="#" onclick="toggleCheckboxes();" title="' . $GLOBALS['LANG']->getLL('label.checkAll', TRUE) . '" class="icon">' .
-                               t3lib_iconWorks::getSpriteIcon('actions-document-select') .
-                               '</a>';
-                       $table[$tr][] = '&nbsp;';
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.id');
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('task');
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.type');
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.frequency');
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.parallel');
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.lastExecution');
-                       $table[$tr][] = $GLOBALS['LANG']->getLL('label.nextExecution');
-                       $tr++;
-
-                               // Loop on all tasks
-                       while (($schedulerRecord = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))) {
-                                       // Define action icons
-                               $editAction = '<a href="' . $GLOBALS['MCONF']['_'] . '&CMD=edit&tx_scheduler[uid]=' . $schedulerRecord['uid'] . '" title="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:edit', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-document-open') . '</a>';
-                               $deleteAction = '<a href="' . $GLOBALS['MCONF']['_'] . '&CMD=delete&tx_scheduler[uid]=' . $schedulerRecord['uid'] . '" onclick="return confirm(\'' . $GLOBALS['LANG']->getLL('msg.delete') . '\');" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:delete', TRUE) . '" class="icon">' . t3lib_iconWorks::getSpriteIcon('actions-edit-delete') . '</a>';
-                               $stopAction = '<a href="' . $GLOBALS['MCONF']['_'] . '&CMD=stop&tx_scheduler[uid]=' . $schedulerRecord['uid'] . '" onclick="return confirm(\'' . $GLOBALS['LANG']->getLL('msg.stop') . '\');" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:stop', TRUE) . '" class="icon"><img ' . t3lib_iconWorks::skinImg($this->backPath, t3lib_extMgm::extRelPath('scheduler') . '/res/gfx/stop.png') . ' alt="'.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:stop') . '" /></a>';
-                                       // Define some default values
-                               $lastExecution = '-';
-                               $isRunning = false;
-                               $executionStatus = 'scheduled';
-                               $executionStatusDetail = '';
-                               $executionStatusOutput = '';
-                               $name = '';
-                               $nextDate = '-';
-                               $execType = '-';
-                               $frequency = '-';
-                               $multiple = '-';
-                               $startExecutionElement = '&nbsp;';
-
-                                       // Restore the serialized task and pass it a reference to the scheduler object
-                               $task = unserialize($schedulerRecord['serialized_task_object']);
-
-                                       // Assemble information about last execution
-                               $context = '';
-                               if (!empty($schedulerRecord['lastexecution_time'])) {
-                                       $lastExecution = date($dateFormat, $schedulerRecord['lastexecution_time']);
-                                       if ($schedulerRecord['lastexecution_context'] == 'CLI') {
-                                               $context = $GLOBALS['LANG']->getLL('label.cron');
-                                       } else {
-                                               $context = $GLOBALS['LANG']->getLL('label.manual');
-                                       }
-                                       $lastExecution .= ' (' . $context . ')';
-                               }
-
-                               if ($this->scheduler->isValidTaskObject($task)) {
-                                       // The task object is valid
-
-                                       $name = htmlspecialchars($registeredClasses[$schedulerRecord['classname']]['title']. ' (' . $registeredClasses[$schedulerRecord['classname']]['extension'] . ')');
-                                       $additionalInformation = $task->getAdditionalInformation();
-                                       if (!empty($additionalInformation)) {
-                                               $name .= '<br />[' . htmlspecialchars($additionalInformation) . ']';
-                                       }
-
-                                               // Check if task currently has a running execution
-                                       if (!empty($schedulerRecord['serialized_executions'])) {
-                                               $isRunning = true;
-                                               $executionStatus = 'running';
-                                       }
-
-                                               // Prepare display of next execution date
-                                               // If task is currently running, date is not displayed (as next hasn't been calculated yet)
-                                               // Also hide the date if task is disabled (the information doesn't make sense, as it will not run anyway)
-                                       if ($isRunning || $schedulerRecord['disable'] == 1) {
-                                               $nextDate = '-';
-                                       }
-                                       else {
-                                               $nextDate = date($dateFormat, $schedulerRecord['nextexecution']);
-                                               if (empty($schedulerRecord['nextexecution'])) {
-                                                       $nextDate = $GLOBALS['LANG']->getLL('none');
-                                               } elseif ($schedulerRecord['nextexecution'] < $GLOBALS['EXEC_TIME']) {
-                                                               // Next execution is overdue, highlight date
-                                                       $nextDate = '<span class="late" title="' . $GLOBALS['LANG']->getLL('status.legend.scheduled') . '">' . $nextDate . '</span>';
-                                                       $executionStatus = 'late';
-                                               }
-                                       }
-
-                                               // Get execution type
-                                       if ($task->getExecution()->getInterval() == 0 && $task->getExecution()->getCronCmd() == '') {
-                                               $execType = $GLOBALS['LANG']->getLL('label.type.single');
-                                               $frequency = '-';
-                                       } else {
-                                               $execType = $GLOBALS['LANG']->getLL('label.type.recurring');
-                                               if ($task->getExecution()->getCronCmd() == '') {
-                                                       $frequency = $task->getExecution()->getInterval();
-                                               } else {
-                                                       $frequency = $task->getExecution()->getCronCmd();
-                                               }
-                                       }
-
-                                               // Get multiple executions setting
-                                       if ($task->getExecution()->getMultiple()) {
-                                               $multiple = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes');
-                                       } else {
-                                               $multiple = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:no');
-                                       }
-
-                                               // Define checkbox
-                                       $startExecutionElement = '<input type="checkbox" name="tx_scheduler[execute][]" value="' . $schedulerRecord['uid'] . '" id="task_' . $schedulerRecord['uid'] . '" class="checkboxes" />';
-
-                                               // Show no action links (edit, delete) if task is running
-                                       $actions = $editAction . $deleteAction;
-                                       if ($isRunning) {
-                                               $actions = $stopAction;
-                                       }
-
-                                               // Check the disable status
-                                               // Row is shown dimmed if task is disabled, unless it is still running
-                                       if ($schedulerRecord['disable'] == 1 && !$isRunning) {
-                                               $tableLayout[$tr] = $disabledTaskRow;
-                                               $executionStatus  = 'disabled';
-                                       }
-
-                                               // Check if the last run failed
-                                       $failureOutput = '';
-                                       if (!empty($schedulerRecord['lastexecution_failure'])) {
-                                                       // Try to get the stored exception object
-                                               $exception = unserialize($schedulerRecord['lastexecution_failure']);
-                                                       // If the exception could not be unserialized, issue a default error message
-                                               if ($exception === FALSE) {
-                                                       $failureDetail = $GLOBALS['LANG']->getLL('msg.executionFailureDefault');
-                                               } else {
-                                                       $failureDetail = sprintf($GLOBALS['LANG']->getLL('msg.executionFailureReport'), $exception->getCode(), $exception->getMessage());
-                                               }
-                                               $failureOutput = ' <img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_failure.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.failure')) . '" title="' . htmlspecialchars($failureDetail) . '" />';
-                                       }
-
-                                               // Format the execution status,
-                                               // including failure feedback, if any
-                                       $executionStatusOutput = '<img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_' . $executionStatus . '.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.' . $executionStatus)) . '" title="' . htmlspecialchars($executionStatusDetail) . '" />' . $failureOutput;
-
-                                       $table[$tr][] = $startExecutionElement;
-                                       $table[$tr][] = $actions;
-                                       $table[$tr][] = $schedulerRecord['uid'];
-                                       $table[$tr][] = $executionStatusOutput;
-                                       $table[$tr][] = $name;
-                                       $table[$tr][] = $execType;
-                                       $table[$tr][] = $frequency;
-                                       $table[$tr][] = $multiple;
-                                       $table[$tr][] = $lastExecution;
-                                       $table[$tr][] = $nextDate;
-
-                               } else {
-                                       // The task object is not valid
-                                       // Prepare to issue an error
-
-                                               /** @var t3lib_FlashMessage $flashMessage */
-                                       $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage',
-                                               sprintf($GLOBALS['LANG']->getLL('msg.invalidTaskClass'), $schedulerRecord['classname']),
-                                               '',
-                                               t3lib_FlashMessage::ERROR
-                                       );
-                                       $executionStatusOutput = $flashMessage->render();
-
-                                       $tableLayout[$tr] = $rowWithSpan;
-                                       $table[$tr][] = $startExecutionElement;
-                                       $table[$tr][] = $deleteAction;
-                                       $table[$tr][] = $schedulerRecord['uid'];
-                                       $table[$tr][] = $executionStatusOutput;
-                               }
-
-                               $tr++;
-                       }
-                               // Render table
-                       $content .= $this->doc->table($table, $tableLayout);
-
-                       $content .= '<input type="submit" class="button" name="go" value="' . $GLOBALS['LANG']->getLL('label.executeSelected') . '" />';
-               }
-
-               if (count($registeredClasses) > 0) {
-                               // Display add new task link
-                       $link = $GLOBALS['MCONF']['_'] . '&CMD=add';
-                       $content .= '<p><a href="' . htmlspecialchars($link) .'"><img '
-                               . t3lib_iconWorks::skinImg($this->backPath, 'gfx/new_el.gif')
-                               . ' alt="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:new', TRUE)
-                               . '" /> ' . $GLOBALS['LANG']->getLL('action.add') . '</a></p>';
-               } else {
-                               /** @var t3lib_FlashMessage $flashMessage */
-                       $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage',
-                               $GLOBALS['LANG']->getLL('msg.noTasksDefined'),
-                               '',
-                               t3lib_FlashMessage::INFO
-                       );
-                       $content .= $flashMessage->render();
-               }
-
-                       // Display legend, if there's at least one registered task
-                       // Also display information about the usage of server time
-               if ($numRows > 0) {
-                       $content .= $this->doc->spacer(20);
-                       $content .= '<h4>' . $GLOBALS['LANG']->getLL('status.legend') . '</h4>
-                       <ul>
-                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_failure.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.failure')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.failure') . '</li>
-                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_late.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.late')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.late') . '</li>
-                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_running.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.running')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.running') . '</li>
-                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_scheduled.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.scheduled')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.scheduled') . '</li>
-                               <li><img ' . t3lib_iconWorks::skinImg(t3lib_extMgm::extRelPath('scheduler'), 'res/gfx/status_disabled.png') . ' alt="' . htmlspecialchars($GLOBALS['LANG']->getLL('status.disabled')) . '" /> ' . $GLOBALS['LANG']->getLL('status.legend.disabled') . '</li>
-                       </ul>';
-                       $content .= $this->doc->spacer(10);
-                       $content .= $this->displayServerTime();
-               }
-
-
-               $GLOBALS['TYPO3_DB']->sql_free_result($res);
-
-               return $content;
-       }
-
-       /**
-        * Saves a task specified in the backend form to the database
-        *
-        * @return      void
-        */
-       protected function saveTask() {
-
-                       // If a task is being edited fetch old task data
-               if (!empty($this->submittedData['uid'])) {
-                       try {
-                               $taskRecord = $this->scheduler->fetchTaskRecord($this->submittedData['uid']);
-                               /**
-                                * @var tx_scheduler_Task
-                                */
-                               $task = unserialize($taskRecord['serialized_task_object']);
-                       } catch (OutOfBoundsException $e) {
-                                       // If the task could not be fetched, issue an error message
-                                       // and exit early
-                               $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.taskNotFound'), $this->submittedData['uid']), t3lib_FlashMessage::ERROR);
-                               return;
-                       }
-
-                               // Register single execution
-                       if ($this->submittedData['type'] == 1) {
-                               $task->registerSingleExecution($this->submittedData['start']);
-
-                               // Else, it's a recurring task
-                       } else {
-                               if (!empty($this->submittedData['croncmd'])) {
-                                               // Definition by cron-like syntax
-
-                                       $interval = 0;
-                                       $cronCmd = $this->submittedData['croncmd'];
-                               } else {
-                                               // Definition by interval
-
-                                       $interval = $this->submittedData['interval'];
-                                       $cronCmd = '';
-                               }
-
-                                       // Register recurring execution
-                               $task->registerRecurringExecution($this->submittedData['start'], $interval, $this->submittedData['end'], $this->submittedData['multiple'], $cronCmd);
-                       }
-
-                               // Set disable flag
-                       $task->setDisabled($this->submittedData['disable']);
-
-                               // Save additional input values
-                       if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) {
-                               $providerObject = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']);
-                               if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
-                                       $providerObject->saveAdditionalFields($this->submittedData, $task);
-                               }
-                       }
-
-                               // Save to database
-                       $result = $this->scheduler->saveTask($task);
-                       if ($result) {
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.updateSuccess'));
-                       } else {
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.updateError'), t3lib_FlashMessage::ERROR);
-                       }
-               } else {
-                               // A new task is being created
-
-                               // Create an instance of chosen class
-                       $task = t3lib_div::makeInstance($this->submittedData['class']);
-
-                       if ($this->submittedData['type'] == 1) {
-                                       // Set up single execution
-                               $task->registerSingleExecution($this->submittedData['start']);
-                       } else {
-                                       // Set up recurring execution
-                               $task->registerRecurringExecution($this->submittedData['start'], $this->submittedData['interval'], $this->submittedData['end'], $this->submittedData['multiple'], $this->submittedData['croncmd']);
-                       }
-
-                               // Save additional input values
-                       if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) {
-                               $providerObject = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']);
-                               if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
-                                       $providerObject->saveAdditionalFields($this->submittedData, $task);
-                               }
-                       }
-
-                               // Set disable flag
-                       $task->setDisabled($this->submittedData['disable']);
-
-                               // Add to database
-                       $result = $this->scheduler->addTask($task);
-                       if ($result) {
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.addSuccess'));
-                       } else {
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.addError'), t3lib_FlashMessage::ERROR);
-                       }
-               }
-       }
-
-
-       /*************************
-        *
-        * INPUT PROCESSING UTILITIES
-        *
-        *************************/
-
-       /**
-        * Checks the submitted data and performs some preprocessing on it
-        *
-        * @return      boolean         True if everything was ok, false otherwise
-        */
-       protected function preprocessData() {
-               $result = true;
-
-                       // Validate id
-               $this->submittedData['uid'] = (empty($this->submittedData['uid'])) ? 0 : intval($this->submittedData['uid']);
-
-                       // Validate selected task class
-               if (!class_exists($this->submittedData['class'])) {
-                       $this->addMessage($GLOBALS['LANG']->getLL('msg.noTaskClassFound'), t3lib_FlashMessage::ERROR);
-               }
-
-                       // Check start date
-               if (empty($this->submittedData['start'])) {
-                       $this->addMessage($GLOBALS['LANG']->getLL('msg.noStartDate'), t3lib_FlashMessage::ERROR);
-                       $result = false;
-               } else {
-                       try {
-                               $timestamp = $this->checkDate($this->submittedData['start']);
-                               $this->submittedData['start'] = $timestamp;
-                       } catch (Exception $e) {
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.invalidStartDate'), t3lib_FlashMessage::ERROR);
-                               $result = false;
-                       }
-               }
-
-                       // Check end date, if recurring task
-               if ($this->submittedData['type'] == 2 && !empty($this->submittedData['end'])) {
-                       try {
-                               $timestamp = $this->checkDate($this->submittedData['end']);
-                               $this->submittedData['end'] = $timestamp;
-
-                               if ($this->submittedData['end'] < $this->submittedData['start']) {
-                                       $this->addMessage($GLOBALS['LANG']->getLL('msg.endDateSmallerThanStartDate'), t3lib_FlashMessage::ERROR);
-                                       $result = false;
-                               }
-                       } catch (Exception $e) {
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.invalidEndDate'), t3lib_FlashMessage::ERROR);
-                               $result = false;
-                       }
-               }
-
-                       // Set default values for interval and cron command
-               $this->submittedData['interval'] = 0;
-               $this->submittedData['croncmd'] = '';
-
-                       // Check type and validity of frequency, if recurring
-               if ($this->submittedData['type'] == 2) {
-                       $frequency = trim($this->submittedData['frequency']);
-
-                       if (empty($frequency)) {
-                                       // Empty frequency, not valid
-
-                               $this->addMessage($GLOBALS['LANG']->getLL('msg.noFrequency'), t3lib_FlashMessage::ERROR);
-                               $result = FALSE;
-                       } else {
-                               $cronErrorCode = 0;
-                               $cronErrorMessage = '';
-
-                                       // Try interpreting the cron command
-                               try {
-                                       tx_scheduler_CronCmd_Normalize::normalize($frequency);
-                                       $this->submittedData['croncmd'] = $frequency;
-                               }
-                                       // If the cron command was invalid, we may still have a valid frequency in seconds
-                               catch (Exception $e) {
-                                               // Store the exception's result
-                                       $cronErrorMessage = $e->getMessage();
-                                       $cronErrorCode = $e->getCode();
-                                               // Check if the frequency is a valid number
-                                               // If yes, assume it is a frequency in seconds, and unset cron error code
-                                       if (is_numeric($frequency)) {
-                                               $this->submittedData['interval'] = intval($frequency);
-                                               unset($cronErrorCode);
-                                       }
-                               }
-                                       // If there's a cron error code, issue validation error message
-                               if (!empty($cronErrorCode)) {
-                                       $this->addMessage(sprintf($GLOBALS['LANG']->getLL('msg.frequencyError'), $cronErrorMessage, $cronErrorCode), t3lib_FlashMessage::ERROR);
-                                       $result = FALSE;
-                               }
-                       }
-               }
-
-                       // Validate additional input fields
-               if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields'])) {
-                       $providerObject = t3lib_div::getUserObj($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'][$this->submittedData['class']]['additionalFields']);
-                       if ($providerObject instanceof tx_scheduler_AdditionalFieldProvider) {
-                                       // The validate method will return true if all went well, but that must not
-                                       // override previous false values => AND the returned value with the existing one
-                               $result &= $providerObject->validateAdditionalFields($this->submittedData, $this);
-                       }
-               }
-
-               return $result;
-       }
-
-       /**
-        * This method checks whether the given string can be considered a valid date or not
-        * Allowed values are anything that matches natural language (see PHP function strtotime())
-        * or TYPO3's date syntax: HH:ii yyyy-mm-dd
-        * If the string is a valid date, the corresponding timestamp is returned.
-        * Otherwise an exception is thrown
-        *
-        * @param       string          $string: string to check
-        * @return      integer         Unix timestamp
-        */
-       protected function checkDate($string) {
-                       // Try with strtotime
-               $timestamp = strtotime($string);
-
-                       // That failed. Try TYPO3's standard date/time input format
-               if ($timestamp === false) {
-                               // Split time and date
-                       $dateParts = t3lib_div::trimExplode(' ', $string, true);
-                               // Proceed if there are indeed two parts
-                               // Extract each component of date and time
-                       if (count($dateParts) == 2) {
-                               list($time, $date) = $dateParts;
-                               list($hour, $minutes) = t3lib_div::trimExplode(':', $time, true);
-                               list($day, $month, $year) = t3lib_div::trimExplode('-', $date, true);
-                                       // Get a timestamp from all these parts
-                               $timestamp = mktime($hour, $minutes, 0, $month, $day, $year);
-                       }
-                               // If the timestamp is still false, throw an exception
-                       if ($timestamp === false) {
-                               throw new InvalidArgumentException('"' . $string . '" seems not to be a correct date.', 1294587694);
-                       }
-               }
-               return $timestamp;
-       }
-
-       /*************************
-        *
-        * APPLICATION LOGIC UTILITIES
-        *
-        *************************/
-
-       /**
-        * This method is used to add a message to the internal queue
-        *
-        * @param       string  the message itself
-        * @param       integer message level (-1 = success (default), 0 = info, 1 = notice, 2 = warning, 3 = error)
-        * @return      void
-        */
-       public function addMessage($message, $severity = t3lib_FlashMessage::OK) {
-               $message = t3lib_div::makeInstance(
-                       't3lib_FlashMessage',
-                       $message,
-                       '',
-                       $severity
-               );
-
-               t3lib_FlashMessageQueue::addMessage($message);
-       }
-
-       /**
-        * This method a list of all classes that have been registered with the Scheduler
-        * For each item the following information is provided, as an associative array:
-        *
-        * ['extension']        =>      Key of the extension which provides the class
-        * ['filename']         =>      Path to the file containing the class
-        * ['title']            =>      String (possibly localized) containing a human-readable name for the class
-        * ['provider']         =>      Name of class that implements the interface for additional fields, if necessary
-        *
-        * The name of the class itself is used as the key of the list array
-        *
-        * @return      array   List of registered classes
-        */
-       protected static function getRegisteredClasses() {
-               $list = array();
-               if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'])) {
-                       foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['scheduler']['tasks'] as $class => $registrationInformation) {
-
-                               $title         = isset($registrationInformation['title'])         ? $GLOBALS['LANG']->sL($registrationInformation['title'])         : '';
-                               $description   = isset($registrationInformation['description'])   ? $GLOBALS['LANG']->sL($registrationInformation['description'])   : '';
-
-                               $list[$class] = array(
-                                       'extension'     => $registrationInformation['extension'],
-                                       'title'         => $title,
-                                       'description'   => $description,
-                                       'provider'              => isset($registrationInformation['additionalFields']) ? $registrationInformation['additionalFields'] : ''
-                               );
-                       }
-               }
-
-               return $list;
-       }
-
-
-       /*************************
-        *
-        * RENDERING UTILITIES
-        *
-        *************************/
-
-       /**
-        * Gets the filled markers that are used in the HTML template.
-        *
-        * @return      array           The filled marker array
-        */
-       protected function getTemplateMarkers() {
-               $markers = array(
-                       'CSH' => t3lib_BEfunc::wrapInHelp('_MOD_tools_txschedulerM1', ''),
-                       'FUNC_MENU' => $this->getFunctionMenu(),
-                       'CONTENT'   => $this->content,
-                       'TITLE'     => $GLOBALS['LANG']->getLL('title'),
-               );
-
-               return $markers;
-       }
-
-       /**
-        * Gets the function menu selector for this backend module.
-        *
-        * @return      string          The HTML representation of the function menu selector
-        */
-       protected function getFunctionMenu() {
-               $functionMenu = t3lib_BEfunc::getFuncMenu(
-                       0,
-                       'SET[function]',
-                       $this->MOD_SETTINGS['function'],
-                       $this->MOD_MENU['function']
-               );
-
-               return $functionMenu;
-       }
-
-       /**
-        * Gets the buttons that shall be rendered in the docHeader.
-        *
-        * @return      array           Available buttons for the docHeader
-        */
-       protected function getDocHeaderButtons() {
-               $buttons = array(
-                       'reload'   => '',
-                       'shortcut' => $this->getShortcutButton(),
-               );
-
-               if (empty($this->CMD) || $this->CMD == 'list') {
-                       $buttons['reload'] = '<a href="' . $GLOBALS['MCONF']['_'] . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.reload', TRUE) . '">' .
-                         t3lib_iconWorks::getSpriteIcon('actions-system-refresh') .
-                 '</a>';
-               }
-
-               return $buttons;
-       }
-
-       /**
-        * Gets the button to set a new shortcut in the backend (if current user is allowed to).
-        *
-        * @return      string          HTML representiation of the shortcut button
-        */
-       protected function getShortcutButton() {
-               $result = '';
-               if ($GLOBALS['BE_USER']->mayMakeShortcut()) {
-                       $result = $this->doc->makeShortcutIcon('', 'function', $this->MCONF['name']);
-               }
-
-               return $result;
-       }
-}
-
-
-if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/scheduler/mod1/index.php'])) {
-       include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/scheduler/mod1/index.php']);
-}
-
-
-
-
 // Make instance:
 $SOBE = t3lib_div::makeInstance('tx_scheduler_Module');
 $SOBE->init();
@@ -1625,5 +39,4 @@ foreach($SOBE->include_once as $INC_FILE) {
 
 $SOBE->main();
 $SOBE->render();
-
-?>
+?>
\ No newline at end of file