--- /dev/null
+<?php
+/**
+ * The Horde_LoginTasks:: class provides a set of methods for dealing with
+ * login tasks to run upon login to Horde applications.
+ *
+ * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_LoginTasks
+ */
+class Horde_LoginTasks
+{
+ /* Interval settings. */
+ // Do task yearly (First login after/on January 1).
+ const YEARLY = 1;
+ // Do task monthly (First login after/on first of month).
+ const MONTHLY = 2;
+ // Do task weekly (First login after/on a Sunday).
+ const WEEKLY = 3;
+ // Do task daily (First login of the day).
+ const DAILY = 4;
+ // Do task every login.
+ const EVERY = 5;
+ // Do task on first login only.
+ const FIRST_LOGIN = 6;
+
+ /* Display styles. */
+ const DISPLAY_CONFIRM_NO = 1;
+ const DISPLAY_CONFIRM_YES = 2;
+ const DISPLAY_AGREE = 3;
+ const DISPLAY_NOTICE = 4;
+ const DISPLAY_NONE = 5;
+
+ /* Priority settings */
+ const PRIORITY_HIGH = 1;
+ const PRIORITY_NORMAL = 2;
+
+ /**
+ * Singleton instance.
+ *
+ * @var array
+ */
+ static protected $_instances = array();
+
+ /**
+ * The Horde_LoginTasks_Tasklist object for this login.
+ *
+ * @var Horde_LoginTasks_Tasklist
+ */
+ protected $_tasklist;
+
+ /**
+ * Was the tasklist init'd in this access?
+ *
+ * @var boolean
+ */
+ protected $_init = false;
+
+ /**
+ * Attempts to return a reference to a concrete Horde_LoginTasks
+ * instance based on $app. It will only create a new instance
+ * if no instance with the same parameters currently exists.
+ *
+ * This method must be invoked as:
+ * $var = &Horde_LoginTasks::singleton($app[, $params]);
+ *
+ * @param string $app See self::__construct().
+ * @param string $url The URL to redirect to when finished.
+ *
+ * @return Horde_LoginTasks The singleton instance.
+ */
+ static public function singleton($app, $url = null)
+ {
+ if (empty(self::$_instances[$app])) {
+ self::$_instances[$app] = new Horde_LoginTasks($app, $url);
+ }
+
+ return self::$_instances[$app];
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param string $app The name of the Horde application.
+ * @param string $url The URL to redirect to when finished.
+ */
+ protected function __construct($app, $url)
+ {
+ $this->_app = $app;
+
+ /* Retrieves a cached tasklist or make sure one is created. */
+ if (isset($_SESSION['horde_logintasks'][$app])) {
+ $this->_tasklist = unserialize($_SESSION['horde_logintasks'][$app]);
+ } else {
+ $this->_createTaskList($url);
+ $this->_init = true;
+ }
+ }
+
+ /**
+ * Destructor.
+ */
+ public function __destruct()
+ {
+ $_SESSION['horde_logintasks'][$this->_app] = serialize($this->_tasklist);
+ }
+
+ /**
+ * Creates the list of login tasks that are available for this session
+ * (stored in a Horde_LoginTasks_Tasklist object).
+ *
+ * @param string $url The URL to redirect to when finished.
+ */
+ protected function _createTaskList($url)
+ {
+ /* Create a new Horde_LoginTasks_Tasklist object. */
+ $this->_tasklist = new Horde_LoginTasks_Tasklist($url);
+
+ /* Get last task run date(s). */
+ $old_error = error_reporting();
+ $last_logintasks = unserialize($GLOBALS['prefs']->getValue('last_logintasks'));
+ error_reporting($old_error);
+ if (!is_array($last_logintasks)) {
+ $last_logintasks = array();
+ }
+
+ /* If this application handles Horde auth, need to add Horde tasks
+ * here. */
+ $app_list = array($this->_app);
+ if (strnatcasecmp($this->_app, Auth::getProvider()) === 0) {
+ array_unshift($app_list, 'horde');
+ }
+
+ foreach ($app_list as $app) {
+ $fileroot = $GLOBALS['registry']->get('fileroot', $app);
+ if (!is_null($fileroot) &&
+ is_dir($fileroot . '/lib/LoginTasks/Task')) {
+ foreach (scandir($fileroot . '/lib/LoginTasks/Task') as $file) {
+ if (stripos($file, '.php') !== false) {
+ $classname = $app . '_LoginTasks_Task_' . substr($file, 0, -4);
+ if (class_exists($classname)) {
+ $tasks[$classname] = $app;
+ if (!isset($lasttasks[$app])) {
+ $lasttasks[$app] = empty($last_logintasks[$app])
+ ? 0
+ : getdate($last_logintasks[$app]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (empty($tasks)) {
+ return;
+ }
+
+ /* Create time objects for today's date and last task run date. */
+ $cur_date = getdate();
+
+ foreach ($tasks as $classname => $app) {
+ $ob = new $classname();
+
+ /* If marked inactive, skip the task. */
+ if (!$ob->active) {
+ continue;
+ }
+
+ $addtask = false;
+
+ if (empty($lasttasks[$app])) {
+ /* If timestamp is empty (= 0), this is the first time the
+ user has logged in. Don't run any other login task
+ operations on the first login. */
+ $addtask = ($ob->interval == self::FIRST_LOGIN);
+ } else {
+ switch ($ob->interval) {
+ case self::YEARLY:
+ $addtask = ($cur_date['year'] > $lasttasks[$app]['year']);
+ break;
+
+ case self::MONTHLY:
+ $addtask = (($cur_date['year'] > $lasttasks[$app]['year']) || ($cur_date['mon'] > $lasttasks[$app]['mon']));
+ break;
+
+ case self::WEEKLY:
+ $addtask = (($cur_date['wday'] < $lasttasks[$app]['wday']) || ((time() - 604800) > $this->_lastRun));
+ break;
+
+ case self::DAILY:
+ $addtask = (($cur_date['year'] > $lasttasks[$app]['year']) || ($cur_date['yday'] > $lasttasks[$app]['yday']));
+ break;
+
+ case self::EVERY:
+ $addtask = true;
+ break;
+ }
+ }
+
+ if ($addtask) {
+ $this->_tasklist->addTask($ob);
+ }
+ }
+ }
+
+ /**
+ * Do operations needed for this login.
+ *
+ * This function will generate the list of tasks to perform during this
+ * login and will redirect to the login tasks page if necessary. This is
+ * the function that should be called from the application upon login.
+ */
+ public function runTasks()
+ {
+ if ($this->_tasklist === true) {
+ return;
+ }
+
+ /* Perform ready tasks now. */
+ foreach ($this->_tasklist->ready() as $key => $val) {
+ if (($val->display == self::DISPLAY_AGREE) ||
+ ($val->display == self::DISPLAY_NOTICE) ||
+ Horde_Util::getFormData('logintasks_confirm_' . $key)) {
+ $val->execute();
+ }
+ }
+
+ $need_display = $this->_tasklist->needDisplay();
+ $tasklist_target = $this->_tasklist->target;
+
+ /* If we've successfully completed every task in the list (or skipped
+ * it), record now as the last time login tasks was run. */
+ if (empty($need_display)) {
+ $lasttasks = unserialize($GLOBALS['prefs']->getValue('last_logintasks'));
+ $lasttasks[$this->_app] = time();
+ if (strnatcasecmp($this->_app, Auth::getProvider()) === 0) {
+ $lasttasks['horde'] = time();
+ }
+ $GLOBALS['prefs']->setValue('last_logintasks', serialize($lasttasks));
+
+ /* This will prevent us from having to store the entire tasklist
+ * object in the session, while still indicating we have
+ * completed the login tasks for this application. */
+ $this->_tasklist = true;
+ }
+
+ if ($this->_init && $need_display) {
+ header('Location: ' . $this->getLoginTasksUrl());
+ exit;
+ } elseif (!$this->_init && !$need_display) {
+ header('Location: ' . $tasklist_target);
+ exit;
+ }
+ }
+
+ /**
+ * Generate the list of tasks that need to be displayed.
+ *
+ * This is the function called from the login tasks page every time it
+ * is loaded.
+ *
+ * @return array The list of tasks that need to be displayed.
+ */
+ public function displayTasks()
+ {
+ return $this->_tasklist->needDisplay(true);
+ }
+
+ /**
+ * Generated the login tasks URL.
+ *
+ * @return string The login tasks URL.
+ */
+ public function getLoginTasksUrl()
+ {
+ return Horde_Util::addParameter(Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/logintasks.php', true), array('app' => $this->_app));
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * Abstract class to allow for modularization of specific login tasks.
+ *
+ * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_LoginTasks
+ */
+abstract class Horde_LoginTasks_Task
+{
+ /**
+ * Should the task be run?
+ *
+ * @var boolean
+ */
+ public $active = true;
+
+ /**
+ * The interval at which to run the task.
+ *
+ * @var integer
+ */
+ public $interval = Horde_LoginTasks::MONTHLY;
+
+ /**
+ * The style of the page output.
+ *
+ * [1] Horde_LoginTasks::DISPLAY_CONFIRM_NO
+ * Horde_LoginTasks::DISPLAY_CONFIRM_YES
+ * Each output from describe() will have a checkbox associated
+ * with it. For each checkbox selected, execute() for that task will
+ * be run. More than 1 confirmation message can be displayed on the
+ * confirmation page at once.
+ *
+ * DISPLAY_CONFIRM_YES will be checked by default, DISPLAY_CONFIRM_NO
+ * will be unchecked by default.
+ *
+ * [2] Horde_LoginTasks::DISPLAY_AGREE
+ * The output from describe() should be text asking the user to
+ * agree/disagree to specified terms. If 'yes' is selected, the POST
+ * variable 'agree' will be set. If 'no' is selected, the POST variable
+ * 'not_agree' will be set. In either case, execute() will ALWAYS be
+ * run.
+ * This style will be displayed on its own confirmation page.
+ *
+ * [3] Horde_LoginTasks::DISPLAY_NOTICE
+ * The output from describe() should be any non-interactive text
+ * desired. There will be a single 'Click to Continue' button below
+ * this text. execute() will ALWAYS be run.
+ * This style will be displayed on its own confirmation page.
+ *
+ * [4] Horde_LoginTasks::DISPLAY_NONE
+ * Don't display any confirmation to the user.
+ *
+ * @var integer
+ */
+ public $display = Horde_LoginTasks::DISPLAY_CONFIRM_YES;
+
+ /**
+ * The priority of the task.
+ *
+ * @var integer
+ */
+ public $priority = Horde_LoginTasks::PRIORITY_NORMAL;
+
+ /**
+ * Do login task (if it has been confirmed).
+ *
+ * @return boolean Whether the login task was successful.
+ */
+ abstract public function execute();
+
+ /**
+ * Return description information for the login task.
+ *
+ * @return string Description that will be displayed on the login task
+ * confirmation page.
+ */
+ abstract public function describe();
+
+}
--- /dev/null
+<?php
+/**
+ * The Horde_LoginTasks_Tasklist:: class is used to store the list of
+ * login tasks that need to be run during this login.
+ *
+ * Copyright 2002-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_LoginTasks
+ */
+class Horde_LoginTasks_Tasklist
+{
+ /**
+ * The URL of the web page to load after login tasks are complete.
+ *
+ * @var string
+ */
+ public $target;
+
+ /**
+ * The list of tasks to run during this login.
+ *
+ * KEY: Task name
+ * VALUE: array => (
+ * 'display' => boolean,
+ * 'task' => integer
+ * )
+ *
+ * @var array
+ */
+ protected $_tasks = array();
+
+ /**
+ * Internal flag for addTask().
+ *
+ * @var boolean
+ */
+ protected $_addFlag = false;
+
+ /**
+ * Current task location pointer.
+ *
+ * @var integer
+ */
+ protected $_ptr = null;
+
+ /**
+ * Constructor.
+ *
+ * @param string $url The target URL to redirect to when finished.
+ */
+ public function __construct($url)
+ {
+ $this->target = $url;
+ }
+
+ /**
+ * Adds a task to the tasklist.
+ *
+ * @param Horde_LoginTasks_Task $task The task to execute.
+ */
+ public function addTask($task)
+ {
+ $tmp = array(
+ 'display' => false,
+ 'task' => $task
+ );
+
+ if (($task->display == Horde_LoginTasks::DISPLAY_AGREE) ||
+ ($task->display == Horde_LoginTasks::DISPLAY_NOTICE)) {
+ $tmp['display'] = true;
+ $this->_addFlag = false;
+ } elseif (($task->display != Horde_LoginTasks::DISPLAY_NONE) &&
+ !$this->_addFlag) {
+ $tmp['display'] = true;
+ $this->_addFlag = true;
+ }
+
+ switch ($task->priority) {
+ case Horde_LoginTasks::PRIORITY_HIGH:
+ array_unshift($this->_tasks, $tmp);
+ break;
+
+ case Horde_LoginTasks::PRIORITY_NORMAL:
+ $this->_tasks[] = $tmp;
+ break;
+ }
+ }
+
+ /**
+ * Returns the list of tasks to perform.
+ *
+ * @return array The list of tasks to perform.
+ */
+ public function ready()
+ {
+ $tmp = array();
+
+ reset($this->_tasks);
+ while (list($k, $v) = each($this->_tasks)) {
+ if ($v['display'] &&
+ (is_null($this->_ptr) || ($k > $this->_ptr))) {
+ break;
+ }
+ $tmp[] = $v['task'];
+ }
+
+ if (!is_null($this->_ptr)) {
+ $this->_tasks = array_slice($this->_tasks, $this->_ptr);
+ $this->_ptr = 0;
+ }
+
+ return $tmp;
+ }
+
+ /**
+ * Returns the next batch of tasks that need display.
+ *
+ * @param boolean $advance If true, advance the internal pointer.
+ *
+ * @return array The list of tasks to display.
+ */
+ public function needDisplay($advance = false)
+ {
+ $tmp = array();
+ $display = null;
+
+ reset($this->_tasks);
+ while (list($k, $v) = each($this->_tasks)) {
+ if (!$v['display'] ||
+ (!is_null($display) && ($v['task']->display != $display))) {
+ break;
+ }
+ $tmp[] = $v['task'];
+ $display = $v['task']->display;
+ }
+
+ if ($advance) {
+ $this->_ptr = count($tmp);
+ }
+
+ return $tmp;
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>LoginTasks</name>
+ <channel>pear.horde.org</channel>
+ <summary>Horde Login Tasks System</summary>
+ <description>The Horde_LoginTasks:: class provides a set of methods for dealing with tasks run upon login to Horde applications.
+ </description>
+ <lead>
+ <name>Michael Slusarz</name>
+ <user>slusarz</user>
+ <email>slusarz@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <date>2009-06-23</date>
+ <version>
+ <release>0.1.0</release>
+ <api>0.1.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>* Renamed Maintenance:: -> Horde_LoginTasks::.
+ * Initial Horde 4 package.</notes>
+ <contents>
+ <dir name="/">
+ <dir name="lib">
+ <dir name="Horde">
+ <dir name="LoginTasks">
+ <file name="Task.php" role="php" />
+ <file name="Tasklist.php" role="php" />
+ </dir> <!-- /lib/Horde/LoginTasks -->
+ <file name="LoginTasks.php" role="php" />
+ </dir> <!-- /lib/Horde -->
+ </dir> <!-- /lib -->
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.5.4</min>
+ </pearinstaller>
+ <package>
+ <name>Util</name>
+ <channel>pear.horde.org</channel>
+ </package>
+ </required>
+ </dependencies>
+ <phprelease>
+ <filelist>
+ <install name="lib/Horde/LoginTasks/Task.php" as="Horde/LoginTasks/Task.php" />
+ <install name="lib/Horde/LoginTasks/Tasklist.php" as="Horde/LoginTasks/Tasklist.php" />
+ <install name="lib/Horde/LoginTasks.php" as="Horde/LoginTasks.php" />
+ </filelist>
+ </phprelease>
+ <changelog>
+ <release>
+ <date>2006-05-08</date>
+ <time>22:26:53</time>
+ <version>
+ <release>0.0.2</release>
+ <api>0.0.2</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>Converted to package.xml 2.0 for pear.horde.org</notes>
+ </release>
+ <release>
+ <date>2003-07-05</date>
+ <version>
+ <release>0.0.1</release>
+ <api>0.0.1</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>Initial release as a PEAR package
+ </notes>
+ </release>
+ </changelog>
+</package>
+