Notification:: (CVS HEAD) -> Horde_Notification::
authorMichael M Slusarz <slusarz@curecanti.org>
Mon, 22 Jun 2009 00:48:32 +0000 (18:48 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Wed, 24 Jun 2009 23:18:47 +0000 (17:18 -0600)
framework/Notification/lib/Horde/Notification.php [new file with mode: 0644]
framework/Notification/lib/Horde/Notification/Event.php [new file with mode: 0644]
framework/Notification/lib/Horde/Notification/Listener.php [new file with mode: 0644]
framework/Notification/lib/Horde/Notification/Listener/Audio.php [new file with mode: 0644]
framework/Notification/lib/Horde/Notification/Listener/Javascript.php [new file with mode: 0644]
framework/Notification/lib/Horde/Notification/Listener/Mobile.php [new file with mode: 0644]
framework/Notification/lib/Horde/Notification/Listener/Status.php [new file with mode: 0644]
framework/Notification/package.xml [new file with mode: 0644]

diff --git a/framework/Notification/lib/Horde/Notification.php b/framework/Notification/lib/Horde/Notification.php
new file mode 100644 (file)
index 0000000..f4ed48d
--- /dev/null
@@ -0,0 +1,240 @@
+<?php
+/**
+ * The Horde_Notification:: class provides a subject-observer pattern for
+ * raising and showing messages of different types and to different
+ * listeners.
+ *
+ * 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  Jan Schneider <jan@horde.org>
+ * @package Horde_Notification
+ */
+class Horde_Notification
+{
+    /**
+     * Horde_Notification instances.
+     *
+     * @var Horde_Notification
+     */
+    protected $_instances = array();
+
+    /**
+     * Hash containing all attached listener objects.
+     *
+     * @var array
+     */
+    protected $_listeners = array();
+
+    /**
+     * The name of the session variable where we store the messages.
+     *
+     * @var string
+     */
+    protected $_stack;
+
+    /**
+     * A Horde_Alarm instance.
+     *
+     * @var Horde_Alarm
+     */
+    protected $_alarm;
+
+    /**
+     * Returns a reference to the global Notification object, only
+     * creating it if it doesn't already exist.
+     *
+     * This method must be invoked as:
+     *   $notification = Horde_Notification::singleton()
+     *
+     * @param string $stack  The name of the message stack to use.
+     *
+     * return Notification  The Horde Notification instance.
+     */
+    static public function singleton($stack = 'horde_notification_stacks')
+    {
+        if (!isset(self::$_instances[$stack])) {
+            self::$_instances[$stack] = new Horde_Notification($stack);
+        }
+
+        return self::$_instances[$stack];
+    }
+
+    /**
+     * Initialize the notification system, set up any needed session
+     * variables, etc.
+     *
+     * @param string $stack  The name of the message stack to use.
+     */
+    protected function __construct($stack)
+    {
+        $this->_stack = $stack;
+
+        /* Make sure the message stack is registered in the session,
+         * and obtain a global-scope reference to it. */
+        if (!isset($_SESSION[$this->_stack])) {
+            $_SESSION[$this->_stack] = array();
+        }
+
+        if (!empty($GLOBALS['conf']['alarms']['driver'])) {
+            $this->_alarm = Horde_Alarm::factory();
+        }
+    }
+
+    /**
+     * Registers a listener with the notification object and includes
+     * the necessary library file dynamically.
+     *
+     * @param string $listener The name of the listener to attach. These names
+     *                         must be unique; further listeners with the same
+     *                         name will be ignored.
+     * @param array $params    A hash containing any additional configuration or
+     *                         connection parameters a listener driver might
+     *                         need.
+     * @param string $class    The class name from which the driver was
+     *                         instantiated if not the default one. If given
+     *                         you have to include the library file containing
+     *                         this class yourself. This is useful if you want
+     *                         the listener driver to be overriden by an
+     *                         application's implementation.
+     *
+     * @return TODO
+     * @throws Horde_Exception
+     */
+    public function attach($listener, $params = array(), $class = null)
+    {
+        $listener = basename($listener);
+        if (!empty($this->_listeners[$listener])) {
+            return $this->_listeners[$listener];
+        }
+
+        if (is_null($class)) {
+            $class = 'Horde_Notification_Listener_' . ucfirst($listener);
+        }
+
+        if (class_exists($class)) {
+            $this->_listeners[$listener] = new $class($params);
+            if (!isset($_SESSION[$this->_stack][$listener])) {
+                $_SESSION[$this->_stack][$listener] = array();
+            }
+            return $this->_listeners[$listener];
+        }
+
+        throw new Horde_Exception(sprintf('Notification listener %s not found.', $listener));
+    }
+
+    /**
+     * Remove a listener from the notification list.
+     *
+     * @param string $listner  The name of the listener to detach.
+     *
+     * @throws Horde_Exception
+     */
+    public function detach($listener)
+    {
+        $listener = basename($listener);
+        if (!isset($this->_listeners[$listener])) {
+            throw new Horde_Exception(sprintf('Notification listener %s not found.', $listener));
+        }
+
+        $list = $this->_listeners[$listener];
+        unset($this->_listeners[$listener], $_SESSION[$this->_stack][$list->getName()]);
+    }
+
+    /**
+     * Add an event to the Horde message stack.
+     *
+     * The event type parameter should begin with 'horde.' unless the
+     * application defines its own Horde_Notification_Listener subclass that
+     * handles additional codes.
+     *
+     * @param mixed $event   Horde_Notification_Event object or message string.
+     * @param integer $type  The type of message: 'horde.error',
+     *                       'horde.warning', 'horde.success', or
+     *                       'horde.message'.
+     * @param array $flags   Array of optional flags that will be passed to the
+     *                       registered listeners.
+     */
+    public function push($event, $type = null, $flags = array())
+    {
+        if (!$event instanceof Horde_Notification_Event &&
+            !$event instanceof PEAR_Error) {
+            /* Transparently create a Horde_Notification_Event object and
+             * set the message attribute. */
+            $event = new Horde_Notification_Event($event);
+        }
+
+        if ($event instanceof PEAR_Error) {
+            if (is_null($type)) {
+                $type = 'horde.error';
+            }
+            Horde::logMessage($event, __FILE__, __LINE__, PEAR_LOG_DEBUG);
+        } elseif (is_null($type)) {
+            $type = 'horde.message';
+        }
+
+        foreach ($this->_listeners as $listener) {
+            if ($listener->handles($type)) {
+                $_SESSION[$this->_stack][$listener->getName()][] = array(
+                    'class' => get_class($event),
+                    'event' => serialize($event),
+                    'flags' => serialize($flags),
+                    'type' => $type
+                );
+            }
+        }
+    }
+
+    /**
+     * Passes the message stack to all listeners and asks them to
+     * handle their messages.
+     *
+     * @param array $options  An array containing display options for the
+     *                        listeners.
+     */
+    public function notify($options = array())
+    {
+        if (!isset($options['listeners'])) {
+            $options['listeners'] = array_keys($this->_listeners);
+        } elseif (!is_array($options['listeners'])) {
+            $options['listeners'] = array($options['listeners']);
+        }
+
+        if ($this->_alarm && in_array('status', $options['listeners'])) {
+            $this->_alarm->notify(Auth::getAuth());
+        }
+
+        foreach ($options['listeners'] as $listener) {
+            if (isset($this->_listeners[$listener])) {
+                $this->_listeners[$listener]->notify($_SESSION[$this->_stack][$this->_listeners[$listener]->getName()], $options);
+            }
+        }
+    }
+
+    /**
+     * Return the number of notification messages in the stack.
+     *
+     * @author David Ulevitch <davidu@everydns.net>
+     *
+     * @param string $my_listener  The name of the listener.
+     *
+     * @return integer  The number of messages in the stack.
+     */
+    public function count($my_listener = null)
+    {
+        if (is_null($my_listener)) {
+            $count = 0;
+            foreach ($this->_listeners as $listener) {
+                if (isset($_SESSION[$this->_stack][$listener->getName()])) {
+                    $count += count($_SESSION[$this->_stack][$listener->getName()]);
+                }
+            }
+            return $count;
+        } else {
+            return @count($_SESSION[$this->_stack][$this->_listeners[$my_listener]->getName()]);
+        }
+    }
+
+}
diff --git a/framework/Notification/lib/Horde/Notification/Event.php b/framework/Notification/lib/Horde/Notification/Event.php
new file mode 100644 (file)
index 0000000..3313792
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * The Horde_Notification_Event:: class provides a container for passing
+ * messages to Horde_Notification_Listener classes.
+ *
+ * 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  Hans Lellelid <hans@velum.net>
+ * @package Horde_Notification
+ */
+class Horde_Notification_Event
+{
+    /**
+     * The message being passed.
+     *
+     * @var string
+     */
+    protected $_message = '';
+
+    /**
+     * If passed, sets the message for this event.
+     *
+     * @param string $message  The text message for this event.
+     */
+    public function __construct($message = null)
+    {
+        if (!is_null($message)) {
+            $this->setMessage($message);
+        }
+    }
+
+    /**
+     * Sets the text message for this event.
+     *
+     * @param string $message  The text message to display.
+     */
+    public function setMessage($message)
+    {
+        $this->_message = $message;
+    }
+
+    /**
+     * Gets the text message for this event.
+     *
+     * @return string  The text message to display.
+     */
+    public function getMessage()
+    {
+        return $this->_message;
+    }
+
+}
diff --git a/framework/Notification/lib/Horde/Notification/Listener.php b/framework/Notification/lib/Horde/Notification/Listener.php
new file mode 100644 (file)
index 0000000..679f3c5
--- /dev/null
@@ -0,0 +1,145 @@
+<?php
+/**
+ * The Horde_Notification_Listener:: class provides functionality for
+ * displaying messages from the message stack as a status line.
+ *
+ * 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  Chuck Hagenbuch <chuck@horde.org>
+ * @package Horde_Notification
+ */
+class Horde_Notification_Listener
+{
+    /**
+     * Array of message types that this listener handles.
+     *
+     * @var array
+     */
+    protected $_handles = array();
+
+    /**
+     * Does this listener handle a certain type of message?
+     *
+     * @param string $type  The message type in question.
+     *
+     * @return boolean  Whether this listener handles the type.
+     */
+    public function handles($type)
+    {
+        return isset($this->_handles[$type]);
+    }
+
+    /**
+     * Return a unique identifier for this listener.
+     *
+     * @return string  Unique id.
+     */
+    public function getName()
+    {
+        return get_class($this);
+    }
+
+    /**
+     * Outputs the status line, sends emails, pages, etc., if there
+     * are any messages on this listener's message stack.
+     *
+     * @param array &$messageStack  The stack of messages.
+     * @param array $options        An array of options.
+     */
+    public function notify(&$messageStacks, $options = array())
+    {
+    }
+
+    /**
+     * Processes one message from the message stack.
+     *
+     * @param array $message  One message hash from the stack.
+     */
+    public function getMessage($message)
+    {
+    }
+
+    /**
+     * Unserialize an event from the message stack, checking to see if the
+     * appropriate class exists and kludging it into a base Notification_Event
+     * object if not.
+     */
+    public function getEvent($message)
+    {
+        $ob = false;
+        if (class_exists($message['class'])) {
+            $ob = @unserialize($message['event']);
+        } else {
+            $ob = @unserialize($message['event']);
+            if (!is_callable(array($ob, 'getMessage'))) {
+                if (isset($ob->_message)) {
+                    $ob = new Horde_Notification_Event($ob->_message);
+                }
+            }
+        }
+
+        /* If we've failed to create a valid Notification_Event object
+         * (or subclass object) so far, return a PEAR_Error. */
+        if (!is_callable(array($ob, 'getMessage'))) {
+            $ob = PEAR::raiseError('Unable to decode message event: ' . $message['event']);
+        }
+
+        /* Specially handle PEAR_Error objects and add userinfo if
+         * it's there. */
+        if (is_callable(array($ob, 'getUserInfo'))) {
+            $userinfo = $ob->getUserInfo();
+            if ($userinfo) {
+                if (is_array($userinfo)) {
+                    $userinfo_elts = array();
+                    foreach ($userinfo as $userinfo_elt) {
+                        if (is_scalar($userinfo_elt)) {
+                            $userinfo_elts[] = $userinfo_elt;
+                        } elseif (is_object($userinfo_elt)) {
+                            if (is_callable(array($userinfo_elt, '__toString'))) {
+                                $userinfo_elts[] = $userinfo_elt->__toString();
+                            } elseif (is_callable(array($userinfo_elt, 'getMessage'))) {
+                                $userinfo_elts[] = $userinfo_elt->getMessage();
+                            }
+                        }
+                    }
+                    $userinfo = implode(', ', $userinfo_elts);
+                }
+
+                $ob->_message = $ob->getMessage() . ' : ' . $userinfo;
+            }
+        }
+
+        return $ob;
+    }
+
+    /**
+     * Unserialize an array of event flags from the message stack.  If this
+     * event has no flags, or the flags array could not be unserialized, an
+     * empty array is returned.
+     *
+     * @return array  An array of flags.
+     */
+    public function getFlags($message)
+    {
+        /* If this message doesn't have any flags, return an empty
+         * array. */
+        if (empty($message['flags'])) {
+            return array();
+        }
+
+        /* Unserialize the flags array from the message. */
+        $flags = @unserialize($message['flags']);
+
+        /* If we couldn't unserialize the flags array, return an empty
+         * array. */
+        if (!is_array($flags)) {
+            return array();
+        }
+
+        return $flags;
+    }
+
+}
diff --git a/framework/Notification/lib/Horde/Notification/Listener/Audio.php b/framework/Notification/lib/Horde/Notification/Listener/Audio.php
new file mode 100644 (file)
index 0000000..30ca298
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/**
+ * The Horde_Notification_Listener_Audio:: class provides functionality for
+ * inserting embedded audio notifications from the stack into the page.
+ *
+ * Copyright 2005-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  Jason M. Felice <jason.m.felice@gmail.com>
+ * @package Horde_Notification
+ */
+class Horde_Notification_Listener_Audio extends Horde_Notification_Listener
+{
+    /**
+     * Constructor.
+     */
+    public function __construct()
+    {
+        $this->_handles = array('audio' => '');
+    }
+
+    /**
+     * Outputs the embedded audio code if there are any messages on the
+     * 'audio' message stack.
+     *
+     * @param array &$messageStack  The stack of messages.
+     * @param array $options        An array of options.
+     */
+    public function notify(&$messageStack, $options = array())
+    {
+        if (count($messageStack)) {
+            while ($message = array_shift($messageStack)) {
+                $this->getMessage($message);
+            }
+        }
+    }
+
+    /**
+     * Outputs one message.
+     *
+     * @param array $message  One message hash from the stack.
+     */
+    public function getMessage($message)
+    {
+        $event = $this->getEvent($message);
+        echo '<embed src="', htmlspecialchars($event->getMessage()),
+             '" width="0" height="0" autostart="true" />';
+    }
+
+}
diff --git a/framework/Notification/lib/Horde/Notification/Listener/Javascript.php b/framework/Notification/lib/Horde/Notification/Listener/Javascript.php
new file mode 100644 (file)
index 0000000..6c18449
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+/**
+ * The Horde_Notification_Listener_Javascript:: class provides functionality
+ * for inserting javascript code from the message stack into the page.
+ *
+ * Copyright 2004-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  Jan Schneider <jan@horde.org>
+ * @package Horde_Notification
+ */
+class Horde_Notification_Listener_Javascript extends Horde_Notification_Listener
+{
+    /**
+     * Constructor.
+     */
+    public function __construct()
+    {
+        $this->_handles = array(
+            'javascript' => '',
+            'javascript-file' => ''
+        );
+    }
+
+    /**
+     * Outputs the javascript code if there are any messages on the
+     * 'javascript' message stack and if the 'notify_javascript' option is set.
+     *
+     * @param array &$messageStack  The stack of messages.
+     * @param array $options        An array of options. Options: 'noscript'
+     */
+    public function notify(&$messageStack, $options = array())
+    {
+        if (!count($messageStack)) {
+            return;
+        }
+
+        if (empty($options['noscript'])) {
+            echo '<script type="text/javascript">//<![CDATA[' . "\n";
+        }
+
+        $files = array();
+        while ($message = array_shift($messageStack)) {
+            $event = $this->getEvent($message);
+            if ($message['type'] == 'javascript') {
+                echo $event->getMessage() . "\n";
+            } elseif ($message['type'] == 'javascript-file') {
+                $files[] = $event->getMessage();
+            }
+        }
+
+        if (empty($options['noscript'])) {
+            echo "//]]></script>\n";
+            if (count($files)) {
+                foreach ($files as $file) {
+                    echo '<script type="text/javascript" src="' . $file . '"></script>' . "\n";
+                }
+            }
+        }
+    }
+
+}
diff --git a/framework/Notification/lib/Horde/Notification/Listener/Mobile.php b/framework/Notification/lib/Horde/Notification/Listener/Mobile.php
new file mode 100644 (file)
index 0000000..8901142
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+/**
+ * The Horde_Notification_Listener_Mobile:: class provides functionality for
+ * displaying messages from the message stack on mobile devices.
+ *
+ * Copyright 2003-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  Chuck Hagenbuch <chuck@horde.org>
+ * @package Horde_Notification
+ */
+class Horde_Notification_Listener_Mobile extends Horde_Notification_Listener_Status
+{
+    /**
+     * The Horde_Mobile:: object that status lines should be added to.
+     *
+     * @var Horde_Mobile
+     */
+    protected $_mobile;
+
+    /**
+     * Constructor.
+     */
+    public function __construct()
+    {
+        $this->_handles = array(
+            'horde.error'   => _("ERR"),
+            'horde.success' => _("SUCCESS"),
+            'horde.warning' => _("WARN"),
+            'horde.message' => _("MSG")
+        );
+    }
+
+    /**
+     * Associate a Horde_Mobile:: object with the listener.
+     *
+     * @param Horde_Mobile  The Horde_Mobile:: object to send status lines to.
+     */
+    public function setMobileObject(&$mobile)
+    {
+        $this->_mobile = &$mobile;
+    }
+
+    /**
+     * Outputs the status line if there are any messages on the 'mobile'
+     * message stack.
+     *
+     * @param array &$messageStack  The stack of messages.
+     * @param array $options        An array of options. Options: 'nospace'
+     */
+    public function notify(&$messageStack, $options = array())
+    {
+        if (!$this->_mobile) {
+            $p = new Horde_Notification_Listener_Status();
+            return $p->notify($messageStack, $options);
+        }
+
+        if (count($messageStack)) {
+            while ($message = array_shift($messageStack)) {
+                $this->getMessage($message);
+            }
+            $t = &$this->_mobile->add(new Horde_Mobile_text("\n"));
+            $t->set('linebreaks', true);
+        }
+    }
+
+    /**
+     * Outputs one message.
+     *
+     * @param array $message  One message hash from the stack.
+     */
+    public function getMessage($message)
+    {
+        if (!$this->_mobile) {
+            $p = new Horde_Notification_Listener_Status();
+            return $p->notify($messageStack, $options);
+        }
+
+        $event = $this->getEvent($message);
+        $this->_mobile->add(new Horde_Mobile_text($this->_handles[$message['type']] . ': ' . strip_tags($event->getMessage())));
+    }
+
+}
diff --git a/framework/Notification/lib/Horde/Notification/Listener/Status.php b/framework/Notification/lib/Horde/Notification/Listener/Status.php
new file mode 100644 (file)
index 0000000..4a4b5ca
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/**
+ * The Horde_Notification_Listener_Status:: class provides functionality for
+ * displaying messages from the message stack as a status line.
+ *
+ * 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  Jan Schneider <jan@horde.org>
+ * @package Horde_Notification
+ */
+class Horde_Notification_Listener_Status extends Horde_Notification_Listener
+{
+    /**
+     * Constructor.
+     */
+    public function __construct()
+    {
+        $this->_handles = array(
+            'horde.error' => array('alerts/error.png', _("Error")),
+            'horde.success' => array('alerts/success.png', _("Success")),
+            'horde.warning' => array('alerts/warning.png', _("Warning")),
+            'horde.message' => array('alerts/message.png', _("Message")),
+            'horde.alarm' => array('alerts/alarm.png', _("Alarm"))
+        );
+    }
+
+    /**
+     * Outputs the status line if there are any messages on the 'status'
+     * message stack.
+     *
+     * @param array &$messageStack  The stack of messages.
+     * @param array $options        An array of options.
+     */
+    public function notify(&$messageStack, $options = array())
+    {
+        if (count($messageStack)) {
+            echo '<ul class="notices">';
+            while ($message = array_shift($messageStack)) {
+                $message = $this->getMessage($message);
+                $message = preg_replace('/^<p class="notice">(.*)<\/p>$/', '<li>$1</li>', $message);
+                echo $message;
+            }
+            echo '</ul>';
+        }
+    }
+
+    /**
+     * Outputs one message.
+     *
+     * @param array $message  One message hash from the stack.
+     */
+    public function getMessage($message)
+    {
+        $event = $this->getEvent($message);
+        $text = $event->getMessage();
+
+        if (!in_array('content.raw', $this->getFlags($message))) {
+            $text = htmlspecialchars($text);
+        }
+
+        return '<li>' . Horde::img($this->_handles[$message['type']][0], $this->_handles[$message['type']][1], '', $GLOBALS['registry']->getImageDir('horde')) . $text . '</li>';
+    }
+
+}
diff --git a/framework/Notification/package.xml b/framework/Notification/package.xml
new file mode 100644 (file)
index 0000000..07ee71d
--- /dev/null
@@ -0,0 +1,113 @@
+<?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>Notification</name>
+ <channel>pear.horde.org</channel>
+ <summary>Horde Notification System</summary>
+ <description>The Horde_Notification:: class provides a subject-observer pattern for raising and showing messages of different types and to different listeners.
+ </description>
+ <lead>
+  <name>Jan Schneider</name>
+  <user>jan</user>
+  <email>jan@horde.org</email>
+  <active>yes</active>
+ </lead>
+ <date>2009-06-24</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>* Initial Horde 4 package.
+ </notes>
+ <contents>
+  <dir name="/">
+   <dir name="lib">
+    <dir name="Horde">
+     <dir name="Notification">
+      <dir name="Listener">
+       <file name="Audio.php" role="php" />
+       <file name="Javascript.php" role="php" />
+       <file name="Mobile.php" role="php" />
+       <file name="Status.php" role="php" />
+      </dir> <!-- /lib/Horde/Notification/Listener -->
+      <file name="Event.php" role="php" />
+      <file name="Listener.php" role="php" />
+     </dir> <!-- /lib/Horde/Notification -->
+     <file baseinstalldir="/Horde" name="Notification.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>
+   <extension>
+    <name>gettext</name>
+   </extension>
+  </required>
+  <optional>
+   <package>
+    <name>Alarm</name>
+    <channel>pear.horde.org</channel>
+   </package>
+   <package>
+    <name>Auth</name>
+    <channel>pear.horde.org</channel>
+   </package>
+  </optional>
+ </dependencies>
+ <phprelease>
+  <filelist>
+   <install name="lib/Horde/Notification/Listener/Audio.php" as="Horde/Notification/Listener/Audio.php" />
+   <install name="lib/Horde/Notification/Listener/Javascript.php" as="Horde/Notification/Listener/Javascript.php" />
+   <install name="lib/Horde/Notification/Listener/Mobile.php" as="Horde/Notification/Listener/Mobile.php" />
+   <install name="lib/Horde/Notification/Listener/Status.php" as="Horde/Notification/Listener/Status.php" />
+   <install name="lib/Horde/Notification/Event.php" as="Horde/Notification/Event.php" />
+   <install name="lib/Horde/Notification/Listener.php" as="Horde/Notification/Listener.php" />
+   <install name="lib/Horde/Notification.php" as="Horde/Notification.php" />
+  </filelist>
+ </phprelease>
+ <changelog>
+  <release>
+   <date>2006-05-08</date>
+   <time>22:52:05</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>
+   <version>
+    <release>0.0.1</release>
+    <api>0.0.1</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2003-07-05</date>
+   <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+   <notes>Initial release as a PEAR package
+   </notes>
+  </release>
+ </changelog>
+</package>