summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGunnar Wrobel <wrobel@gentoo.org>2008-08-19 12:50:26 +0000
committerGunnar Wrobel <wrobel@gentoo.org>2008-08-19 12:50:26 +0000
commit1fc46d5f5a4493b568972bbe65ed6b185d6efced (patch)
treefdb4e84c0b29347cba47a633fd89afa6c3affe33 /www-apps/horde-webmail/files
parentVersion bump. (diff)
downloadgentoo-2-1fc46d5f5a4493b568972bbe65ed6b185d6efced.tar.gz
gentoo-2-1fc46d5f5a4493b568972bbe65ed6b185d6efced.tar.bz2
gentoo-2-1fc46d5f5a4493b568972bbe65ed6b185d6efced.zip
Added horde-webmail-1.1.2.
(Portage version: 2.1.4.4)
Diffstat (limited to 'www-apps/horde-webmail/files')
-rw-r--r--www-apps/horde-webmail/files/horde-webmail-1.1.1_kolab.patch4154
1 files changed, 0 insertions, 4154 deletions
diff --git a/www-apps/horde-webmail/files/horde-webmail-1.1.1_kolab.patch b/www-apps/horde-webmail/files/horde-webmail-1.1.1_kolab.patch
deleted file mode 100644
index eef1e76b23a1..000000000000
--- a/www-apps/horde-webmail/files/horde-webmail-1.1.1_kolab.patch
+++ /dev/null
@@ -1,4154 +0,0 @@
-diff -r f7b1e151bdb5 config/conf.php
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/config/conf.php Wed Aug 13 21:37:22 2008 +0200
-@@ -0,0 +1,113 @@
-+<?php
-+/* CONFIG START. DO NOT CHANGE ANYTHING IN OR AFTER THIS LINE. */
-+// $Horde: horde/config/conf.xml,v 1.230 2008/05/26 11:51:43 jan Exp $
-+$conf['vhosts'] = false;
-+$conf['debug_level'] = E_ALL;
-+$conf['max_exec_time'] = 0;
-+$conf['compress_pages'] = true;
-+$conf['umask'] = 077;
-+$conf['use_ssl'] = 2;
-+$conf['server']['name'] = $_SERVER['SERVER_NAME'];
-+$conf['server']['port'] = $_SERVER['SERVER_PORT'];
-+$conf['urls']['pretty'] = false;
-+$conf['safe_ips'] = array();
-+$conf['session']['name'] = 'Horde';
-+$conf['session']['use_only_cookies'] = false;
-+$conf['session']['cache_limiter'] = 'nocache';
-+$conf['session']['timeout'] = 0;
-+$conf['cookie']['domain'] = $_SERVER['SERVER_NAME'];
-+$conf['cookie']['path'] = '/';
-+$conf['sql']['database'] = dirname(__FILE__) . '/../storage/horde.db';
-+$conf['sql']['mode'] = '0640';
-+$conf['sql']['charset'] = 'utf-8';
-+$conf['sql']['phptype'] = 'sqlite';
-+$conf['auth']['admins'] = array('manager');
-+$conf['auth']['checkip'] = true;
-+$conf['auth']['checkbrowser'] = true;
-+$conf['auth']['alternate_login'] = false;
-+$conf['auth']['redirect_on_logout'] = false;
-+$conf['auth']['params']['login_block'] = true;
-+$conf['auth']['params']['login_block_count'] = 3;
-+$conf['auth']['params']['login_block_time'] = 5;
-+$conf['auth']['driver'] = 'kolab';
-+$conf['signup']['allow'] = false;
-+$conf['log']['priority'] = PEAR_LOG_DEBUG;
-+$conf['log']['ident'] = 'HORDE';
-+$conf['log']['params'] = array();
-+$conf['log']['name'] = dirname(__FILE__) . '/../log/horde.log';
-+$conf['log']['params']['append'] = true;
-+$conf['log']['type'] = 'file';
-+$conf['log']['enabled'] = true;
-+$conf['log_accesskeys'] = false;
-+$conf['prefs']['driver'] = 'kolab_imap';
-+$conf['alarms']['params']['driverconfig'] = 'horde';
-+$conf['alarms']['params']['ttl'] = 300;
-+$conf['alarms']['driver'] = 'sql';
-+$conf['datatree']['params']['driverconfig'] = 'horde';
-+$conf['datatree']['driver'] = 'sql';
-+$conf['group']['driver'] = 'kolab';
-+$conf['group']['cache'] = false;
-+$conf['perms']['driverconfig'] = 'horde';
-+$conf['perms']['driver'] = 'sql';
-+$conf['share']['no_sharing'] = false;
-+$conf['share']['any_group'] = false;
-+$conf['share']['cache'] = true;
-+$conf['share']['driver'] = 'kolab';
-+$conf['cache']['default_lifetime'] = 1800;
-+$conf['cache']['params']['dir'] = Horde::getTempDir();
-+$conf['cache']['params']['sub'] = 0;
-+$conf['cache']['driver'] = 'file';
-+$conf['lock']['driver'] = 'none';
-+$conf['token']['driver'] = 'none';
-+$conf['mailer']['params']['auth'] = false;
-+$conf['mailer']['type'] = 'smtp';
-+$conf['mailformat']['brokenrfc2231'] = false;
-+$conf['tmpdir'] = dirname(__FILE__) . '/../tmp/';
-+$conf['vfs']['params']['vfsroot'] = dirname(__FILE__) . '/../storage';
-+$conf['vfs']['type'] = 'file';
-+$conf['sessionhandler']['type'] = 'none';
-+$conf['sessionhandler']['memcache'] = false;
-+$conf['image']['convert'] = '/usr/bin/convert';
-+$conf['mime']['magic_db'] = '/etc/mime.types';
-+$conf['problems']['email'] = 'webmaster@example.com';
-+$conf['problems']['maildomain'] = 'example.com';
-+$conf['problems']['tickets'] = false;
-+$conf['problems']['attachments'] = true;
-+$conf['menu']['apps'] = array();
-+$conf['menu']['always'] = false;
-+$conf['menu']['links']['help'] = 'all';
-+$conf['menu']['links']['help_about'] = true;
-+$conf['menu']['links']['options'] = 'authenticated';
-+$conf['menu']['links']['problem'] = 'all';
-+$conf['menu']['links']['login'] = 'all';
-+$conf['menu']['links']['logout'] = 'authenticated';
-+$conf['hooks']['permsdenied'] = false;
-+$conf['hooks']['username'] = false;
-+$conf['hooks']['preauthenticate'] = false;
-+$conf['hooks']['postauthenticate'] = false;
-+$conf['hooks']['authldap'] = false;
-+$conf['hooks']['groupldap'] = false;
-+$conf['portal']['fixed_blocks'] = array();
-+$conf['accounts']['driver'] = 'null';
-+$conf['user']['verify_from_addr'] = false;
-+$conf['imsp']['enabled'] = false;
-+$conf['kolab']['ldap']['server'] = 'localhost';
-+$conf['kolab']['ldap']['port'] = 389;
-+$conf['kolab']['ldap']['basedn'] = 'dc=example,dc=com';
-+$conf['kolab']['ldap']['phpdn'] = 'cn=nobody,cn=internal,dc=example,dc=com';
-+$conf['kolab']['ldap']['phppw'] = 'dummy';
-+$conf['kolab']['imap']['server'] = 'localhost';
-+$conf['kolab']['imap']['port'] = 143;
-+$conf['kolab']['imap']['sieveport'] = 2000;
-+$conf['kolab']['imap']['maildomain'] = 'example.com';
-+$conf['kolab']['imap']['virtdomains'] = true;
-+$conf['kolab']['smtp']['server'] = 'localhost';
-+$conf['kolab']['smtp']['port'] = 25;
-+$conf['kolab']['misc']['multidomain'] = false;
-+$conf['kolab']['cache_folders'] = true;
-+$conf['kolab']['enabled'] = true;
-+$conf['memcache']['enabled'] = false;
-+/* CONFIG END. DO NOT CHANGE ANYTHING IN OR BEFORE THIS LINE. */
-+if (file_exists(dirname(__FILE__) . '/kolab.php')) {
-+ require_once(dirname(__FILE__) . '/kolab.php');
-+}
-diff -r f7b1e151bdb5 config/kolab.php
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/config/kolab.php Wed Aug 13 21:37:22 2008 +0200
-@@ -0,0 +1,34 @@
-+<?php
-+/* Add additional admins here */
-+$conf['auth']['admins'] = array('manager');
-+
-+/* Add your horde vhost hostname here */
-+$conf['cookie']['domain'] = 'webmail.example.com';
-+
-+/* Add the path to the vhost install here (the value of the -d switch when you used webapp-config) */
-+$conf['cookie']['path'] = '/';
-+
-+/* The email address of your sys admin */
-+$conf['problems']['email'] = 'hostmaster@example.com';
-+
-+/* Primary mail domain of your Kolab server */
-+$conf['problems']['maildomain'] = 'pardus.de';
-+
-+/* The hostname of your LDAP server (usually the same as the hostname of the Kolab server) */
-+$conf['kolab']['ldap']['server'] = 'localhost';
-+
-+/* Base DN of your LDAP server */
-+$conf['kolab']['ldap']['basedn'] = 'dc=example,dc=com';
-+
-+/* php_dn from your /kolab/etc/kolab/kolab.conf */
-+$conf['kolab']['ldap']['phpdn'] = 'cn=nobody,cn=internal,dc=example,dc=com';
-+
-+/* php_pw from your /kolab/etc/kolab/kolab.conf */
-+$conf['kolab']['ldap']['phppw'] = 'MY_SECRET_PASSWORD';
-+
-+/* Hostname of your IMAP server (usually the same as the hostname of the Kolab server) */
-+$conf['kolab']['imap']['server'] = 'localhost';
-+
-+/* Primary mail domain of your Kolab server */
-+$conf['kolab']['imap']['maildomain'] = 'example.com';
-+?>
-diff -r f7b1e151bdb5 config/prefs.php
---- a/config/prefs.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/config/prefs.php Wed Aug 13 21:37:22 2008 +0200
-@@ -357,7 +357,7 @@
-
- // UI theme
- $_prefs['theme'] = array(
-- 'value' => 'bluewhite',
-+ 'value' => 'silver',
- 'locked' => false,
- 'shared' => true,
- 'type' => 'select',
-diff -r f7b1e151bdb5 imp/config/conf.php
---- a/imp/config/conf.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/imp/config/conf.php Wed Aug 13 21:37:22 2008 +0200
-@@ -1,7 +1,8 @@
- <?php
- /* CONFIG START. DO NOT CHANGE ANYTHING IN OR AFTER THIS LINE. */
- // $Horde: imp/config/conf.xml,v 1.53.2.33 2008/05/06 17:54:04 slusarz Exp $
--$conf['spell']['driver'] = '';
-+$conf['spell']['driver'] = 'aspell';
-+$conf['utils']['gnupg'] = '/usr/bin/gpg';
- $conf['utils']['gnupg_keyserver'] = array('pgp.mit.edu');
- $conf['utils']['gnupg_timeout'] = 10;
- $conf['menu']['apps'] = array();
-@@ -52,8 +53,8 @@
- $conf['hooks']['signature'] = false;
- $conf['hooks']['trailer'] = false;
- $conf['hooks']['fetchmail_filter'] = false;
--$conf['hooks']['mbox_redirect'] = false;
--$conf['hooks']['mbox_icon'] = false;
-+$conf['hooks']['mbox_redirect'] = true;
-+$conf['hooks']['mbox_icon'] = true;
- $conf['hooks']['spam_bounce'] = false;
- $conf['hooks']['msglist_format'] = false;
- $conf['maillog']['use_maillog'] = true;
-diff -r f7b1e151bdb5 imp/config/hooks.php
---- a/imp/config/hooks.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/imp/config/hooks.php Wed Aug 13 21:37:22 2008 +0200
-@@ -426,6 +426,9 @@
- case 'contact':
- return $GLOBALS['registry']->get('webroot', 'turba');
-
-+ case 'prefs':
-+ return $GLOBALS['registry']->get('webroot', 'horde') . '/services/prefs.php?app=horde';
-+
- default:
- return '';
- }
-@@ -476,6 +479,14 @@
- 'alt' => _("Contacts")
- );
- break;
-+
-+ case 'prefs':
-+ $icons[$name] = array(
-+ 'icon' => 'prefs.png',
-+ 'icondir' => $GLOBALS['registry']->getImageDir('horde'),
-+ 'alt' => _("Preferences")
-+ );
-+ break;
- }
- }
-
-diff -r f7b1e151bdb5 imp/config/prefs.php
---- a/imp/config/prefs.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/imp/config/prefs.php Wed Aug 13 21:37:22 2008 +0200
-@@ -24,7 +24,7 @@
- 'column' => _("General Options"),
- 'label' => _("Server and Folder Information"),
- 'desc' => _("Change mail server and folder settings."),
-- 'members' => array('use_vinbox', 'subscribe', 'folderselect',
-+ 'members' => array('use_vinbox', 'use_vtask', 'subscribe', 'folderselect',
- 'trashselect', 'spamselect')
- );
- }
-@@ -267,6 +267,14 @@
- 'shared' => false,
- 'type' => 'checkbox',
- 'desc' => _("Display Virtual Inbox?"));
-+
-+// display Virtual Tasks?
-+$_prefs['use_vtask'] = array(
-+ 'value' => 1,
-+ 'locked' => false,
-+ 'shared' => false,
-+ 'type' => 'checkbox',
-+ 'desc' => _("Display Virtual Tasks?"));
-
- // use IMAP subscribe?
- $_prefs['subscribe'] = array(
-@@ -1463,3 +1471,10 @@
- 'locked' => false,
- 'shared' => false,
- 'type' => 'implicit');
-+
-+// virtual task identifier
-+$_prefs['vtask_id'] = array(
-+ 'value' => '',
-+ 'locked' => false,
-+ 'shared' => false,
-+ 'type' => 'implicit');
-diff -r f7b1e151bdb5 imp/config/servers.php
---- a/imp/config/servers.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/imp/config/servers.php Wed Aug 13 21:37:22 2008 +0200
-@@ -215,10 +215,30 @@
-
- /* Example configurations: */
-
--$servers['imap'] = array(
-- 'name' => 'IMAP Server',
-- 'server' => 'localhost',
-- 'hordeauth' => false,
-- 'protocol' => 'imap/notls',
-- 'port' => 143,
--);
-+if ($GLOBALS['conf']['kolab']['enabled']) {
-+ require_once 'Horde/Kolab.php';
-+
-+ if (!is_callable('Kolab', 'getServer')) {
-+ $server = $GLOBALS['conf']['kolab']['imap']['server'];
-+ } else {
-+ $server = Kolab::getServer('imap');
-+ }
-+
-+ $servers['kolab'] = array(
-+ 'name' => 'Kolab Cyrus IMAP Server',
-+ 'server' => $server,
-+ 'hordeauth' => 'full',
-+ 'protocol' => 'imap/notls/novalidate-cert',
-+ 'port' => $GLOBALS['conf']['kolab']['imap']['port'],
-+ 'maildomain' => $GLOBALS['conf']['kolab']['imap']['maildomain'],
-+ 'realm' => '',
-+ 'preferred' => '',
-+ 'quota' => array(
-+ 'driver' => 'imap',
-+ 'params' => array('hide_quota_when_unlimited' => true),
-+ ),
-+ 'acl' => array(
-+ 'driver' => 'rfc2086',
-+ ),
-+ );
-+}
-diff -r f7b1e151bdb5 imp/folders.php
---- a/imp/folders.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/imp/folders.php Wed Aug 13 21:37:22 2008 +0200
-@@ -212,6 +212,7 @@
- if (!empty($folder_list)) {
- ($actionID == 'poll_folder') ? $imptree->addPollList($folder_list) : $imptree->removePollList($folder_list);
- $imp_search->createVINBOXFolder();
-+ $imp_search->createVTaskFolder();
- }
- break;
-
-diff -r f7b1e151bdb5 imp/lib/IMAP/Tree.php
---- a/imp/lib/IMAP/Tree.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/imp/lib/IMAP/Tree.php Wed Aug 13 21:37:22 2008 +0200
-@@ -2367,6 +2367,10 @@
- $row['specialvfolder'] = true;
- $row['icon'] = 'folders/inbox.png';
- $row['alt'] = _("Virtual INBOX Folder");
-+ } elseif ($GLOBALS['imp_search']->isVTaskFolder($mailbox['v'])) {
-+ $row['specialvfolder'] = true;
-+ $row['icon'] = 'folders/inbox.png';
-+ $row['alt'] = _("Virtual Task Folder");
- }
- }
- } else {
-diff -r f7b1e151bdb5 imp/lib/Search.php
---- a/imp/lib/Search.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/imp/lib/Search.php Wed Aug 13 21:37:22 2008 +0200
-@@ -96,6 +96,7 @@
- foreach ($this->_getVFolderList() as $key => $val) {
- if (!empty($val['vfolder']) &&
- !$this->isVTrashFolder($key) &&
-+ !$this->isVTaskFolder($key) &&
- !$this->isVINBOXFolder($key)) {
- $this->_updateIMPTree('add', $key, $val['label']);
- $_SESSION['imp']['search']['q'][$key] = $val;
-@@ -103,6 +104,7 @@
- }
- }
- $this->createVINBOXFolder();
-+ $this->createVTaskFolder();
- $this->createVTrashFolder();
- }
-
-@@ -428,6 +430,71 @@
- }
-
- /**
-+ * Add a virtual task folder for the current user.
-+ */
-+ function createVTaskFolder()
-+ {
-+ /* Initialize IMP_Tree. */
-+ require_once IMP_BASE . '/lib/IMAP/Tree.php';
-+ $imptree = &IMP_Tree::singleton();
-+
-+ /* Delete the current Virtual task folder, if it exists. */
-+ $vtask_id = $GLOBALS['prefs']->getValue('vtask_id');
-+ if (!empty($vtask_id)) {
-+ $this->deleteSearchQuery($vtask_id);
-+ }
-+
-+ if (!$GLOBALS['prefs']->getValue('use_vtask')) {
-+ return;
-+ }
-+
-+ /* Create Virtual TASK with nav_poll list. Filter out any nav_poll
-+ * entries that don't exist. Sort the list also. */
-+ $flist = $imptree->getPollList(true, true);
-+
-+ require_once IMP_BASE . '/lib/IMAP/Search.php';
-+ $query1 = new IMP_IMAP_Search_Query();
-+ $query1->seen(false);
-+ $query1->deleted(false);
-+
-+ $query2 = new IMP_IMAP_Search_Query();
-+ $query2->flagged(true);
-+ $query2->deleted(false);
-+
-+ $query = new IMP_IMAP_Search_Query();
-+ $query->imapOr($query1);
-+ $query->imapOr($query2);
-+
-+ $label = _("Virtual TASKS");
-+
-+ $this->_saveVFolder = false;
-+ if (empty($vtask_id)) {
-+ $vtask_id = $this->addVFolder($query, $flist, array(), $label);
-+ $GLOBALS['prefs']->setValue('vtask_id', $vtask_id);
-+ } else {
-+ $this->addVFolder($query, $flist, array(), $label, $vtask_id);
-+ }
-+ $this->_saveVFolder = true;
-+ $_SESSION['imp']['search']['vtask_id'] = $vtask_id;
-+ }
-+
-+ /**
-+ * Determines whether a virtual folder ID is the Virtual TASK Folder.
-+ *
-+ * @param string $id The search query id to use (by default, will use
-+ * the current ID set in the object).
-+ *
-+ * @return boolean True if the virutal folder ID is the Virtual task
-+ * folder.
-+ */
-+ function isVTaskFolder($id = null)
-+ {
-+ $id = $this->_strip($id);
-+ $vtask_id = $GLOBALS['prefs']->getValue('vtask_id');
-+ return (!empty($vtask_id) && ($id == $vtask_id));
-+ }
-+
-+ /**
- * Is the current active folder an editable Virtual Folder?
- *
- * @param string $id The search query id to use (by default, will use
-@@ -439,7 +506,7 @@
- function isEditableVFolder($id = null)
- {
- $id = $this->_strip($id);
-- return ($this->isVFolder($id) && !$this->isVTrashFolder($id) && !$this->isVINBOXFolder($id));
-+ return ($this->isVFolder($id) && !$this->isVTrashFolder($id) && !$this->isVINBOXFolder($id) && !$this->isVTaskFolder($id));
- }
-
- /**
-@@ -518,7 +585,7 @@
- $id = $this->_strip($id);
- if (empty($_SESSION['imp']['search']['q'][$id])) {
- return '';
-- } elseif ($this->isVINBOXFolder($id) || $this->isVTrashFolder($id)) {
-+ } elseif ($this->isVINBOXFolder($id) || $this->isVTrashFolder($id) || $this->isVTaskFolder($id)) {
- return $_SESSION['imp']['search']['q'][$id]['label'];
- } elseif (empty($_SESSION['imp']['search']['q'][$id]['uiinfo'])) {
- unset($_SESSION['imp']['search']['q'][$id]);
-diff -r f7b1e151bdb5 imp/lib/prefs.php
---- a/imp/lib/prefs.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/imp/lib/prefs.php Wed Aug 13 21:37:22 2008 +0200
-@@ -165,7 +165,7 @@
- }
-
- if (($prefs->isDirty('use_vtrash') && $prefs->getValue('use_vtrash')) ||
-- $prefs->isDirty('use_vinbox')) {
-+ $prefs->isDirty('use_vinbox') || $prefs->isDirty('use_vtask')) {
- require_once IMP_BASE . '/lib/Search.php';
- $imp_search = new IMP_Search();
- $imp_search->sessionSetup(true);
-diff -r f7b1e151bdb5 imp/mailbox.php
---- a/imp/mailbox.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/imp/mailbox.php Wed Aug 13 21:37:23 2008 +0200
-@@ -248,7 +248,8 @@
- /* Determine if we are going to show the Hide/Purge Deleted Message links. */
- if (!$prefs->getValue('use_trash') &&
- !$prefs->getValue('use_vtrash') &&
-- !$GLOBALS['imp_search']->isVINBOXFolder()) {
-+ !$GLOBALS['imp_search']->isVINBOXFolder() &&
-+ !$GLOBALS['imp_search']->isVTaskFolder()) {
- $showdelete = array('hide' => ($sortpref['by'] != SORTTHREAD), 'purge' => true);
- } else {
- $showdelete = array('hide' => false, 'purge' => false);
-@@ -335,7 +336,7 @@
- $vtrash = null;
- if ($search_mbox) {
- $unread = 0;
-- if ($imp_search->isVINBOXFolder()) {
-+ if ($imp_search->isVINBOXFolder() || $imp_search->isVTaskFolder()) {
- $unread = $imp_mailbox->getMessageCount();
- } elseif ($imp_search->isVTrashFolder()) {
- $vtrash = $imp_search->createSearchID($search_mbox);
-diff -r f7b1e151bdb5 ingo/config/backends.php
---- a/ingo/config/backends.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/ingo/config/backends.php Wed Aug 13 21:37:23 2008 +0200
-@@ -40,6 +40,8 @@
- * give them permissions to do so. If you want to enable this
- * feature, you need to set this parameter to true.
- */
-+
-+if (!$GLOBALS['conf']['kolab']['enabled']) {
-
- /* IMAP Example */
- $backends['imap'] = array(
-@@ -297,6 +299,8 @@
- 'scriptparams' => array()
- );
-
-+}
-+
- /* Kolab Example (using Sieve) */
- if ($GLOBALS['conf']['kolab']['enabled']) {
- require_once 'Horde/Kolab.php';
-diff -r f7b1e151bdb5 kronolith/config/conf.php
---- a/kronolith/config/conf.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/kronolith/config/conf.php Wed Aug 13 21:37:23 2008 +0200
-@@ -1,12 +1,11 @@
- <?php
- /* CONFIG START. DO NOT CHANGE ANYTHING IN OR AFTER THIS LINE. */
- // $Horde: kronolith/config/conf.xml,v 1.14.10.5 2007/12/20 14:12:23 jan Exp $
--$conf['calendar']['params']['table'] = 'kronolith_events';
--$conf['calendar']['params']['driverconfig'] = 'horde';
--$conf['calendar']['driver'] = 'sql';
--$conf['storage']['params']['table'] = 'kronolith_storage';
--$conf['storage']['params']['driverconfig'] = 'horde';
--$conf['storage']['driver'] = 'sql';
-+$conf['calendar']['driver'] = 'kolab';
-+$conf['storage']['driver'] = 'kolab';
-+$conf['storage']['default_domain'] = '';
-+$conf['storage']['freebusy']['protocol'] = 'https';
-+$conf['storage']['freebusy']['port'] = 443;
- $conf['metadata']['keywords'] = false;
- $conf['autoshare']['shareperms'] = 'none';
- $conf['holidays']['enable'] = true;
-@@ -14,3 +13,6 @@
- $conf['menu']['import_export'] = true;
- $conf['menu']['apps'] = array();
- /* CONFIG END. DO NOT CHANGE ANYTHING IN OR BEFORE THIS LINE. */
-+if (file_exists(dirname(__FILE__) . '/kolab.php')) {
-+ require_once(dirname(__FILE__) . '/kolab.php');
-+}
-diff -r f7b1e151bdb5 kronolith/config/kolab.php
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/kronolith/config/kolab.php Wed Aug 13 21:37:23 2008 +0200
-@@ -0,0 +1,10 @@
-+<?php
-+/* Primary mail domain of your Kolab server */
-+$conf['storage']['default_domain'] = 'example.com';
-+
-+/* Hostname of your IMAP server (usually the same as the hostname of the Kolab server) */
-+$conf['reminder']['server_name'] = 'localhost';
-+
-+/* The email address of your sys admin */
-+$conf['reminder']['from_addr'] = 'hostmaster@example.com';
-+?>
-diff -r f7b1e151bdb5 lib/Horde/Kolab/IMAP.php
---- a/lib/Horde/Kolab/IMAP.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/Horde/Kolab/IMAP.php Wed Aug 13 21:37:23 2008 +0200
-@@ -1021,7 +1021,9 @@
- function generateUID()
- {
- do {
-- $key = md5(uniqid(mt_rand(), true));
-+ $key = date('YmdHis') . '.'
-+ . substr(str_pad(base_convert(microtime(), 10, 36), 16, uniqid(mt_rand()), STR_PAD_LEFT), -16)
-+ . '@' . $GLOBALS['conf']['server']['name'];
- } while($this->objectUidExists($key));
-
- return $key;
-diff -r f7b1e151bdb5 lib/Horde/Kolab/XML/contact.php
---- a/lib/Horde/Kolab/XML/contact.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/Horde/Kolab/XML/contact.php Wed Aug 13 21:37:23 2008 +0200
-@@ -294,6 +294,9 @@
- function _load(&$children)
- {
- $object = $this->loadArray($children, $this->_fields_specific);
-+ if (is_a($object, 'PEAR_Error')) {
-+ return $object;
-+ }
-
- // Handle name fields
- if (isset($object['name'])) {
-diff -r f7b1e151bdb5 lib/Horde/Kolab/XML/distributionlist.php
---- a/lib/Horde/Kolab/XML/distributionlist.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/Horde/Kolab/XML/distributionlist.php Wed Aug 13 21:37:23 2008 +0200
-@@ -60,6 +60,9 @@
- function _load(&$children)
- {
- $object = $this->loadArray($children, $this->_fields_specific);
-+ if (is_a($object, 'PEAR_Error')) {
-+ return $object;
-+ }
-
- // Map the display-name of a kolab dist list to horde's lastname attribute
- if (isset($object['display-name'])) {
-diff -r f7b1e151bdb5 lib/Horde/Kolab/XML/jobtype.php
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/lib/Horde/Kolab/XML/jobtype.php Wed Aug 13 21:37:23 2008 +0200
-@@ -0,0 +1,56 @@
-+<?php
-+/**
-+ * @package Horde_Kolab
-+ *
-+ * $Horde: framework/Kolab/Kolab/Format/XML/hprefs.php,v 1.1 2008/06/16 11:46:09 wrobel Exp $
-+ */
-+
-+/**
-+ * Kolab XML handler for timetracking jobtypes
-+ *
-+ * $Horde: framework/Kolab/Kolab/Format/XML/hprefs.php,v 1.1 2008/06/16 11:46:09 wrobel Exp $
-+ *
-+ * Copyright 2008 The Horde Project (http://www.horde.org/)
-+ *
-+ * @author Gunnar Wrobel <wrobel@pardus.de>
-+ * @package Horde_Kolab
-+ */
-+class Kolab_Format_XML_jobtype extends Kolab_Format_XML {
-+ /**
-+ * Specific data fields for the jobtype object
-+ *
-+ * @var Kolab
-+ */
-+ var $_fields_specific;
-+
-+ /**
-+ * Constructor
-+ */
-+ function Kolab_Format_XML_jobtype()
-+ {
-+ $this->_root_name = 'jobtype';
-+
-+ /** Specific preferences fields, in kolab format specification order
-+ */
-+ $this->_fields_specific = array(
-+ 'billable' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_INTEGER,
-+ 'value' => HORDE_KOLAB_XML_VALUE_MAYBE_MISSING,
-+ ),
-+ 'enabled' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_INTEGER,
-+ 'value' => HORDE_KOLAB_XML_VALUE_MAYBE_MISSING,
-+ ),
-+ 'name' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
-+ ),
-+ 'rate' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_MAYBE_MISSING,
-+ ),
-+ );
-+
-+ parent::Kolab_Format_XML();
-+ }
-+}
-diff -r f7b1e151bdb5 lib/Horde/Kolab/XML/note.php
---- a/lib/Horde/Kolab/XML/note.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/Horde/Kolab/XML/note.php Wed Aug 13 21:37:23 2008 +0200
-@@ -64,6 +64,9 @@
- function _load(&$children)
- {
- $object = $this->loadArray($children, $this->_fields_specific);
-+ if (is_a($object, 'PEAR_Error')) {
-+ return $object;
-+ }
-
- $object['desc'] = $object['summary'];
- unset($object['summary']);
-diff -r f7b1e151bdb5 lib/Horde/Kolab/XML/task.php
---- a/lib/Horde/Kolab/XML/task.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/Horde/Kolab/XML/task.php Wed Aug 13 21:37:23 2008 +0200
-@@ -109,6 +109,9 @@
- function _load(&$children)
- {
- $object = $this->loadArray($children, $this->_fields_specific);
-+ if (is_a($object, 'PEAR_Error')) {
-+ return $object;
-+ }
-
- $object['name'] = $object['summary'];
- unset($object['summary']);
-diff -r f7b1e151bdb5 lib/Horde/Kolab/XML/timetrack.php
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/lib/Horde/Kolab/XML/timetrack.php Wed Aug 13 21:37:23 2008 +0200
-@@ -0,0 +1,90 @@
-+<?php
-+/**
-+ * @package Horde_Kolab
-+ *
-+ * $Horde: framework/Kolab/Kolab/Format/XML/hprefs.php,v 1.1 2008/06/16 11:46:09 wrobel Exp $
-+ */
-+
-+/**
-+ * Kolab XML handler for time tracking entries
-+ *
-+ * $Horde: framework/Kolab/Kolab/Format/XML/hprefs.php,v 1.1 2008/06/16 11:46:09 wrobel Exp $
-+ *
-+ * Copyright 2008 The Horde Project (http://www.horde.org/)
-+ *
-+ * @author Gunnar Wrobel <wrobel@pardus.de>
-+ * @package Horde_Kolab
-+ */
-+class Kolab_Format_XML_timetrack extends Kolab_Format_XML {
-+ /**
-+ * Specific data fields for the jobtype object
-+ *
-+ * @var Kolab
-+ */
-+ var $_fields_specific;
-+
-+ /**
-+ * Constructor
-+ */
-+ function Kolab_Format_XML_timetrack()
-+ {
-+ $this->_root_name = 'timetrack';
-+
-+ /** Specific preferences fields, in kolab format specification order
-+ */
-+ $this->_fields_specific = array(
-+ 'client' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
-+ ),
-+ 'employee' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
-+ ),
-+ 'type' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
-+ ),
-+ 'hours' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
-+ ),
-+ 'billable' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_INTEGER,
-+ 'value' => HORDE_KOLAB_XML_VALUE_MAYBE_MISSING,
-+ ),
-+ 'submitted' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_INTEGER,
-+ 'value' => HORDE_KOLAB_XML_VALUE_DEFAULT,
-+ 'default' => 0,
-+ ),
-+ 'exported' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_INTEGER,
-+ 'value' => HORDE_KOLAB_XML_VALUE_DEFAULT,
-+ 'default' => 0,
-+ ),
-+ 'date' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_DATE,
-+ 'value' => HORDE_KOLAB_XML_VALUE_MAYBE_MISSING,
-+ ),
-+ 'description' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_MAYBE_MISSING,
-+ ),
-+ 'note' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_MAYBE_MISSING,
-+ ),
-+ 'rate' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_NOT_EMPTY,
-+ ),
-+ 'costobject' => array(
-+ 'type' => HORDE_KOLAB_XML_TYPE_STRING,
-+ 'value' => HORDE_KOLAB_XML_VALUE_MAYBE_MISSING,
-+ ),
-+ );
-+
-+ parent::Kolab_Format_XML();
-+ }
-+}
-diff -r f7b1e151bdb5 lib/Horde/Prefs/kolab.php
---- a/lib/Horde/Prefs/kolab.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/Horde/Prefs/kolab.php Wed Aug 13 21:37:23 2008 +0200
-@@ -1,5 +1,6 @@
- <?php
-
-+require_once 'Horde/Auth.php';
- require_once 'Horde/Prefs/ldap.php';
- require_once 'Horde/Kolab.php';
-
-@@ -42,7 +43,8 @@
- 'searchpw' => $GLOBALS['conf']['kolab']['ldap']['phppw'],
- 'uid' => 'mail');
-
-- parent::Prefs_ldap($user, $password, $scope, $params, $caching);
-+ parent::Prefs_ldap(Auth::getAuth(), Auth::getCredential('password'),
-+ $scope, $params, $caching);
- }
-
- }
-diff -r f7b1e151bdb5 lib/Horde/iCalendar.php
---- a/lib/Horde/iCalendar.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/Horde/iCalendar.php Wed Aug 13 21:37:23 2008 +0200
-@@ -152,6 +152,41 @@
- 'value' => $value,
- 'values' => $values
- );
-+ }
-+ }
-+
-+ /**
-+ * Sets an attribute empty.
-+ *
-+ * @param string $name The name of the attribute.
-+ * @param array $params Array containing any addition parameters for
-+ * this attribute.
-+ * @param boolean $append True to append the attribute, False to replace
-+ * the first matching attribute found.
-+ */
-+ function setAttributeEmpty($name, $params = array(), $append = false)
-+ {
-+ switch ($name) {
-+ case 'EXDATE':
-+ case 'RDATE':
-+ $this->setAttribute($name, array(), $params, $append, true);
-+ break;
-+ case 'COMPLETED':
-+ case 'CREATED':
-+ case 'DCREATED':
-+ case 'LAST-MODIFIED':
-+ case 'DTEND':
-+ case 'DTSTART':
-+ case 'DTSTAMP':
-+ case 'DUE':
-+ case 'AALARM':
-+ case 'RECURRENCE-ID':
-+ /* These values expect a date and there is no sensible
-+ default so we better leave them alone for now. */
-+ break;
-+ default:
-+ $this->setAttribute($name, '', $params, $append);
-+ break;
- }
- }
-
-diff -r f7b1e151bdb5 lib/SyncML/Backend.php
---- a/lib/SyncML/Backend.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/SyncML/Backend.php Wed Aug 13 21:37:23 2008 +0200
-@@ -574,6 +574,24 @@
- }
-
- /**
-+ * Checks if the entry specified by $cuid has been modified on the server.
-+ *
-+ * @param string $databaseURI URI of Database to sync. Like
-+ * calendar, tasks, contacts or notes.
-+ * May include optional parameters:
-+ * tasks?options=ignorecompleted.
-+ * @param string $cuid Client ID of this entry
-+ * @param integer $from_ts Start timestamp.
-+ *
-+ * @return boolean True if the client entry has been modified on
-+ * the server. False otherwise.
-+ */
-+ function unchanged($databaseURI, $cuid, $from_ts)
-+ {
-+ die ("Not implemented!");
-+ }
-+
-+ /**
- * Authenticates the user at the backend.
- *
- * For some types of authentications (notably auth:basic) the username
-diff -r f7b1e151bdb5 lib/SyncML/Backend/Horde.php
---- a/lib/SyncML/Backend/Horde.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/SyncML/Backend/Horde.php Wed Aug 13 21:37:23 2008 +0200
-@@ -202,6 +202,11 @@
- __FILE__, __LINE__, PEAR_LOG_DEBUG);
- continue;
- }
-+ if ($suid_ts > $to_ts) {
-+ // Add delayed to the next sync operation
-+ $this->logMessage("Add ignored, lies in sync future: $suid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
-+ continue;
-+ }
- $this->logMessage(
- "Adding to client from db $database, server id $suid",
- __FILE__, __LINE__, PEAR_LOG_DEBUG);
-@@ -250,6 +255,11 @@
- // mirror that back to the client.
- $this->logMessage("Changed on server after sent from client: $suid ignored",
- __FILE__, __LINE__, PEAR_LOG_DEBUG);
-+ continue;
-+ }
-+ if ($suid_ts > $to_ts) {
-+ // Change delayed to the next sync operation
-+ $this->logMessage("Change ignored, lies in sync future: $suid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
- continue;
- }
- $cuid = $this->_getCuid($database, $suid);
-@@ -311,6 +321,11 @@
- $this->logMessage("Deleted on server after request from client: $suid ignored",
- __FILE__, __LINE__, PEAR_LOG_DEBUG);
- continue;
-+ }
-+ if ($suid_ts > $to_ts) {
-+ // Delete delayed to the next sync operation
-+ $this->logMessage("Delete ignored, lies in sync future: $suid", __FILE__, __LINE__, PEAR_LOG_DEBUG);
-+ continue;
- }
- $cuid = $this->_getCuid($database, $suid);
- if (!$cuid) {
-@@ -509,6 +524,71 @@
- $this->createUidMap($database, $cuid, $suid, $ts);
- }
-
-+ return true;
-+ }
-+
-+ /**
-+ * Checks if the entry specified by $cuid has been modified on the server.
-+ *
-+ * @param string $databaseURI URI of Database to sync. Like
-+ * calendar, tasks, contacts or notes.
-+ * May include optional parameters:
-+ * tasks?options=ignorecompleted.
-+ * @param string $cuid Client ID of this entry
-+ * @param integer $from_ts Last server sync time.
-+ *
-+ * @return boolean True if the client entry has been modified on
-+ * the server. False otherwise.
-+ */
-+ function getConflict($databaseURI, $cuid, $server_ts)
-+ {
-+ global $registry;
-+
-+ $database = $this->_normalize($databaseURI);
-+
-+ // Only server needs to do a cuid<->suid map
-+ if ($this->_backendMode == SYNCML_BACKENDMODE_SERVER) {
-+ $suid = $this->_getSuid($database, $cuid);
-+ } else {
-+ $suid = $cuid;
-+ }
-+ $this->logMessage("checking modification date of entry suid $suid in $database", __FILE__, __LINE__, PEAR_LOG_DEBUG);
-+
-+ if ($suid) {
-+ $mod_ts = $registry->call($database . '/getActionTimestamp', array($suid, 'modify', SyncML_Backend::getParameter($databaseURI,'source')));
-+ $client_ts = $this->_getChangeTS($database, $suid);
-+ // Check that the last server anchor is smaller than the
-+ // last modification stamp (this means that a change
-+ // occurred after the last sync started). This might still
-+ // be a client change so check that the last client update
-+ // also happened before the last modification)
-+ if ($server_ts < $mod_ts && $client_ts < $mod_ts) {
-+ // Duplicate the server entry
-+ $this->logMessage("Conflict detected. Returning conflicting server entry $suid.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
-+ $device = &$_SESSION['SyncML.state']->getDevice();
-+ $contentType = $device->getPreferredContentType($databaseURI);
-+ return $this->retrieveEntry($databaseURI, $suid, $contentType);
-+ }
-+ }
-+ return false;
-+ }
-+
-+ function duplicateConflict($databaseURI, $content)
-+ {
-+ global $registry;
-+
-+ $database = $this->_normalize($databaseURI);
-+ $device = &$_SESSION['SyncML.state']->getDevice();
-+ $contentType = $device->getPreferredContentType($databaseURI);
-+ $content = preg_replace('/(\r\n|\r|\n)UID:.*?(\r\n|\r|\n)/', '\1', $content, 1);
-+ $duid = $registry->call($database. '/import',
-+ array($content, $contentType,
-+ SyncML_Backend::getParameter($databaseURI,'source')));
-+ if (is_a($duid, 'PEAR_Error')) {
-+ $this->logMessage("duplicating entry failed.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
-+ return false;
-+ }
-+ $this->logMessage("duplicated server entry to $duid.", __FILE__, __LINE__, PEAR_LOG_DEBUG);
- return true;
- }
-
-diff -r f7b1e151bdb5 lib/SyncML/Constants.php
---- a/lib/SyncML/Constants.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/SyncML/Constants.php Wed Aug 13 21:37:23 2008 +0200
-@@ -64,7 +64,7 @@
- define('RESPONSE_PARTIAL_CONTENT', 206);
- define('RESPONSE_CONFLICT_RESOLVED_WITH_MERGE', 207);
- define('RESPONSE_CONFLICT_RESOLVED_WITH_CLIENT_WINNING', 208);
--define('RESPONSE_CONFILCT_RESOLVED_WITH_DUPLICATE', 209);
-+define('RESPONSE_CONFLICT_RESOLVED_WITH_DUPLICATE', 209);
- define('RESPONSE_DELETE_WITHOUT_ARCHIVE', 210);
- define('RESPONSE_ITEM_NO_DELETED', 211);
- define('RESPONSE_AUTHENTICATION_ACCEPTED', 212);
-diff -r f7b1e151bdb5 lib/SyncML/Device.php
---- a/lib/SyncML/Device.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/SyncML/Device.php Wed Aug 13 21:37:23 2008 +0200
-@@ -161,12 +161,81 @@
- SYNCML_LOGFILE_DATA,
- "\nInput received from client ($contentType):\n$content\n");
-
-+ $content = $this->_completeEmptyAttributes($content, $contentType);
-+
- // Always remove client UID. UID will be seperately passed in XML.
- $content = preg_replace('/(\r\n|\r|\n)UID:.*?(\r\n|\r|\n)/',
- '\1', $content, 1);
-
- return array($content, $contentType);
- }
-+
-+ /**
-+ * Complete any attributes that the client supports but did not
-+ * provide. In case the user did delete an attribute on the client
-+ * this action is required to indicate to the server that the
-+ * attribute needs to be deleted. A completely missing attribute
-+ * would be considered as "no change" by the server.
-+ *
-+ * @param string $content The content to convert
-+ * @param string $contentType The contentType of the content
-+ *
-+ * @return string The converted content
-+ */
-+ function _completeEmptyAttributes($content, $contentType)
-+ {
-+
-+ $di = $_SESSION['SyncML.state']->deviceInfo;
-+
-+ if (empty($di) || !isset($di->_CTCap) || !isset($di->_CTCap[$contentType])) {
-+ return $content;
-+ }
-+
-+ require_once 'Horde/iCalendar.php';
-+ $iCal = new Horde_iCalendar();
-+ if (!$iCal->parsevCalendar($content)) {
-+ // We cant parse the content, return it unchanged
-+ return $content;
-+ }
-+ $components = $iCal->getComponents();
-+ $attributes = $di->_CTCap[$contentType];
-+
-+ foreach ($components as $component) {
-+ foreach ($attributes as $name => $properties) {
-+ if ($name == 'BEGIN' || $name == 'END') {
-+ continue;
-+ }
-+ $values = $component->getAllAttributes($name);
-+ if (!isset($properties->_params)) {
-+ if (empty($values)) {
-+ // Undefined attribute -> replace it with
-+ // the correct empty value
-+ $component->setAttributeEmpty($name);
-+ }
-+ } else {
-+ foreach ($properties->_params as $key => $property) {
-+ if (!empty($values)) {
-+ $present = true;
-+ } else {
-+ $present = false;
-+ foreach ($values as $value) {
-+ if (in_array($key, array_keys($value['params']))) {
-+ $present = true;
-+ break;
-+ }
-+ }
-+ }
-+ if (!$present) {
-+ // Undefined attribute -> replace it with
-+ // the correct empty value
-+ $component->setAttributeEmpty($name, array($key => null), true);
-+ }
-+ }
-+ }
-+ }
-+ }
-+ return $iCal->exportvCalendar();
-+ }
-
- /**
- * Converts the content from the backend to a format suitable for the
-diff -r f7b1e151bdb5 lib/SyncML/Sync.php
---- a/lib/SyncML/Sync.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/SyncML/Sync.php Wed Aug 13 21:37:23 2008 +0200
-@@ -214,7 +214,13 @@
- }
- } elseif ($item->elementType =='Delete') {
- /* Handle client delete requests. */
-+ $duplicate = $backend->getConflict($hordedatabase, $cuid, $this->_serverAnchorLast);
- $ok = $backend->deleteEntry($database, $cuid);
-+ $duplicated = false;
-+ if ($duplicate) {
-+ $duplicated = $backend->duplicateConflict($hordedatabase, $duplicate);
-+ }
-+
- if (!$ok && $tasksincalendar) {
- $backend->logMessage(
- 'Task ' . $cuid . ' deletion sent with calendar request',
-@@ -224,8 +230,14 @@
-
- if ($ok) {
- $this->_client_delete_count++;
-- $item->responseCode = RESPONSE_OK;
- $backend->logMessage('Deleted entry ' . $suid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
-+ if (!$duplicated) {
-+ $item->responseCode = RESPONSE_OK;
-+ } else {
-+ $this->_client_add_count++;
-+ $backend->logMessage('Duplicated entry ' . $suid . ' due to client/server conflict', __FILE__, __LINE__, PEAR_LOG_INFO);
-+ $item->responseCode = RESPONSE_CONFLICT_RESOLVED_WITH_DUPLICATE;
-+ }
- } else {
- $this->_errors++;
- $item->responseCode = RESPONSE_ITEM_NO_DELETED;
-@@ -234,13 +246,24 @@
-
- } elseif ($item->elementType == 'Replace') {
- /* Handle client replace requests. */
-+ $duplicate = $backend->getConflict($hordedatabase, $cuid, $this->_serverAnchorLast);
- $suid = $backend->replaceEntry($hordedatabase, $content,
- $contentType, $cuid);
-+ $duplicated = false;
-+ if ($duplicate) {
-+ $duplicated = $backend->duplicateConflict($hordedatabase, $duplicate);
-+ }
-
- if (!is_a($suid, 'PEAR_Error')) {
- $this->_client_replace_count++;
-- $item->responseCode = RESPONSE_OK;
- $backend->logMessage('Replaced entry ' . $suid . ' due to client request', __FILE__, __LINE__, PEAR_LOG_DEBUG);
-+ if (!$duplicated) {
-+ $item->responseCode = RESPONSE_OK;
-+ } else {
-+ $this->_client_add_count++;
-+ $backend->logMessage('Duplicated entry ' . $suid . ' due to client/server conflict', __FILE__, __LINE__, PEAR_LOG_INFO);
-+ $item->responseCode = RESPONSE_CONFLICT_RESOLVED_WITH_DUPLICATE;
-+ }
- } else {
- $backend->logMessage($suid->message, __FILE__, __LINE__, PEAR_LOG_DEBUG);
-
-diff -r f7b1e151bdb5 lib/core.php
---- a/lib/core.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/lib/core.php Wed Aug 13 21:37:23 2008 +0200
-@@ -31,6 +31,12 @@
- * include_path, you must add an ini_set() call here to add their location to
- * the include_path. */
- ini_set('include_path', dirname(__FILE__) . PATH_SEPARATOR . dirname(__FILE__) . '/../pear');
-+ini_set('log_errors', true);
-+ini_set('display_errors', '0');
-+ini_set('error_log', dirname(__FILE__) . '/../log/php-errors.log');
-+session_save_path(dirname(__FILE__) . '/../tmp/');
-+ini_set('upload_tmp_dir', dirname(__FILE__) . '/../tmp/');
-+putenv('TMPDIR=' . dirname(__FILE__) . '/../tmp/');
-
- /* PEAR base class. */
- include_once 'PEAR.php';
-diff -r f7b1e151bdb5 log/.htaccess
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/log/.htaccess Wed Aug 13 21:37:23 2008 +0200
-@@ -0,0 +1,1 @@
-+Deny from All
-\ No newline at end of file
-diff -r f7b1e151bdb5 mnemo/config/conf.php
---- a/mnemo/config/conf.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/mnemo/config/conf.php Wed Aug 13 21:37:23 2008 +0200
-@@ -1,9 +1,8 @@
- <?php
- /* CONFIG START. DO NOT CHANGE ANYTHING IN OR AFTER THIS LINE. */
- // $Horde: mnemo/config/conf.xml,v 1.17.10.1 2007/12/20 14:17:38 jan Exp $
--$conf['storage']['params']['table'] = 'mnemo_memos';
--$conf['storage']['params']['driverconfig'] = 'horde';
--$conf['storage']['driver'] = 'sql';
-+$conf['storage']['driver'] = 'kolab';
-+$conf['utils']['gnupg'] = '/usr/bin/gpg';
- $conf['menu']['print'] = true;
- $conf['menu']['import_export'] = true;
- $conf['menu']['apps'] = array();
-diff -r f7b1e151bdb5 nag/config/conf.php
---- a/nag/config/conf.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/config/conf.php Wed Aug 13 21:37:23 2008 +0200
-@@ -1,9 +1,7 @@
- <?php
- /* CONFIG START. DO NOT CHANGE ANYTHING IN OR AFTER THIS LINE. */
- // $Horde: nag/config/conf.xml,v 1.25.10.2 2007/12/20 14:23:06 jan Exp $
--$conf['storage']['params']['table'] = 'nag_tasks';
--$conf['storage']['params']['driverconfig'] = 'horde';
--$conf['storage']['driver'] = 'sql';
-+$conf['storage']['driver'] = 'kolab';
- $conf['menu']['print'] = true;
- $conf['menu']['import_export'] = true;
- $conf['menu']['apps'] = array();
-diff -r f7b1e151bdb5 nag/lib/Block/tree_menu.php
---- a/nag/lib/Block/tree_menu.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/lib/Block/tree_menu.php Wed Aug 13 21:37:23 2008 +0200
-@@ -39,6 +39,15 @@
- array('icon' => 'add.png',
- 'icondir' => $icondir,
- 'url' => Util::addParameter($add, array('tasklist_id' => $name))));
-+
-+ $tree->addNode($parent . $name,
-+ $parent,
-+ $tasklist->get('name'),
-+ $indent + 1,
-+ false,
-+ array('icon' => 'nag.png',
-+ 'icondir' => $icondir,
-+ 'url' => Util::addParameter(Horde::applicationUrl('list.php'), array('tasklist_id' => $name))));
- }
-
- $tree->addNode($parent . '__search',
-diff -r f7b1e151bdb5 nag/lib/Driver.php
---- a/nag/lib/Driver.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/lib/Driver.php Wed Aug 13 21:37:23 2008 +0200
-@@ -208,13 +208,14 @@
- * @param boolean $private Whether the task is private.
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- *
- * @return array array(ID,UID) of new task
- */
- function add($name, $desc, $start = 0, $due = 0, $priority = 0,
- $estimate = 0.0, $completed = 0, $category = '', $alarm = 0,
- $uid = null, $parent = '', $private = false, $owner = null,
-- $assignee = null)
-+ $assignee = null, $recurrence = null)
- {
- if (is_null($uid)) {
- $uid = $this->generateUID();
-@@ -225,7 +226,7 @@
-
- $taskId = $this->_add($name, $desc, $start, $due, $priority, $estimate,
- $completed, $category, $alarm, $uid, $parent,
-- $private, $owner, $assignee);
-+ $private, $owner, $assignee, $recurrence);
- if (is_a($taskId, 'PEAR_Error')) {
- return $taskId;
- }
-@@ -273,11 +274,13 @@
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
- * @param integer $completed_date The task's completion date.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- */
- function modify($taskId, $name, $desc, $start = 0, $due = 0, $priority = 0,
- $estimate = 0.0, $completed = 0, $category = '',
- $alarm = 0, $parent = '', $private = false,
-- $owner = null, $assignee = null, $completed_date = null)
-+ $owner = null, $assignee = null, $completed_date = null,
-+ $recurrence = null)
- {
- /* Retrieve unmodified task. */
- $task = $this->get($taskId);
-@@ -293,7 +296,7 @@
- $modify = $this->_modify($taskId, $name, $desc, $start, $due,
- $priority, $estimate, $completed, $category,
- $alarm, $parent, $private, $owner, $assignee,
-- $completed_date);
-+ $completed_date, $recurrence);
- if (is_a($modify, 'PEAR_Error')) {
- return $modify;
- }
-@@ -546,6 +549,13 @@
- var $private;
-
- /**
-+ * Recurrence information for a periodic task
-+ *
-+ * @var Nag_Recurrence
-+ */
-+ var $recurrence;
-+
-+ /**
- * URL to view the task.
- *
- * @var string
-@@ -659,6 +669,11 @@
- $key = 'id';
- } elseif ($key == 'parent') {
- $key = 'parent_id';
-+ } elseif ($key == 'recurrence' && is_array($val)) {
-+ require_once NAG_BASE . '/lib/Recurrence.php';
-+ $recurrence = new Nag_Recurrence($task['due']);
-+ $recurrence->fromHash($val);
-+ $val = $recurrence;
- }
- $this->$key = $val;
- }
-@@ -684,7 +699,8 @@
- $this->private,
- $this->owner,
- $this->assignee,
-- $this->completed_date);
-+ $this->completed_date,
-+ $this->recurrence);
- }
-
- /**
-@@ -1012,6 +1028,12 @@
- */
- function toHash()
- {
-+ if ($this->recurs()) {
-+ $recurrence = $this->recurrence->toHash();
-+ } else {
-+ $recurrence = null;
-+ }
-+
- return array('tasklist_id' => $this->tasklist,
- 'task_id' => $this->id,
- 'uid' => $this->uid,
-@@ -1028,7 +1050,8 @@
- 'completed' => $this->completed,
- 'completed_date' => $this->completed_date,
- 'alarm' => $this->alarm,
-- 'private' => $this->private);
-+ 'private' => $this->private,
-+ 'recurrence' => $recurrence);
- }
-
- /**
-@@ -1299,4 +1322,54 @@
- }
- }
-
-+ /**
-+ * Returns whether this task is a recurring task.
-+ *
-+ * @return boolean True if this is a recurring task.
-+ */
-+ function recurs()
-+ {
-+ return isset($this->recurrence) &&
-+ !$this->recurrence->hasRecurType(NAG_RECUR_NONE);
-+ }
-+
-+ /**
-+ * Toggles completion status of this task. Moves a recurring task
-+ * to the next occurence on completion.
-+ */
-+ function toggleComplete()
-+ {
-+ if ($this->completed) {
-+ $this->completed_date = null;
-+ $this->completed = false;
-+ return;
-+ }
-+
-+ if ($this->recurs()) {
-+ /* Get current occurrence (task due date) */
-+ $current = new Horde_Date($this->due);
-+ /* Advance this occurence by a day to indicate that we want the
-+ * following occurence (Recurrence uses days as minimal time
-+ * duration between occurrences). */
-+ $current->mday++;
-+ /* Get the next occurence. */
-+ $next = $this->recurrence->nextActiveRecurrence($current);
-+ if ($next) {
-+ if (!empty($this->start)) {
-+ /* The task has a delayed start that should be moved forward
-+ * by the same timespan.
-+ */
-+ $this->start += $next->timestamp() - $this->due;
-+ }
-+ $this->due = $next->timestamp();
-+ $this->completed = false;
-+ $this->recurrence->addCompletion($next->year, $next->month,
-+ $next->mday);
-+ return;
-+ }
-+ }
-+
-+ $this->completed_date = time();
-+ $this->completed = true;
-+ }
- }
-diff -r f7b1e151bdb5 nag/lib/Driver/kolab.php
---- a/nag/lib/Driver/kolab.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/lib/Driver/kolab.php Wed Aug 13 21:37:23 2008 +0200
-@@ -114,17 +114,19 @@
- * @param boolean $private Whether the task is private.
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- *
- * @return string The Nag ID of the new task.
- */
- function _add($name, $desc, $start = 0, $due = 0, $priority = 0,
- $completed = 0, $estimate = 0.0, $category = '', $alarm = 0,
- $uid = null, $parent = null, $private = false, $owner = null,
-- $assignee = null)
-+ $assignee = null, $recurrence = null)
- {
- return $this->_wrapper->add($name, $desc, $start, $due, $priority,
- $completed, $estimate, $category, $alarm,
-- $uid, $parent, $private, $owner, $assignee);
-+ $uid, $parent, $private, $owner, $assignee,
-+ $recurrence);
- }
-
- /**
-@@ -145,18 +147,21 @@
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
- * @param integer $completed_date The task's completion date.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- *
- * @return boolean Indicates if the modification was successfull.
- */
- function _modify($taskId, $name, $desc, $start = 0, $due = 0, $priority = 0,
- $estimate = 0.0, $completed = 0, $category = '',
- $alarm = 0, $parent = null, $private = false,
-- $owner = null, $assignee = null, $completed_date = null)
-+ $owner = null, $assignee = null, $completed_date = null,
-+ $recurrence = null)
- {
- return $this->_wrapper->modify($taskId, $name, $desc, $start, $due,
- $priority, $estimate, $completed,
- $category, $alarm, $parent, $private,
-- $owner, $assignee, $completed_date);
-+ $owner, $assignee, $completed_date,
-+ $recurrence);
- }
-
- /**
-@@ -271,6 +276,9 @@
- */
- function Nag_Driver_kolab_wrapper($tasklist, &$kolab)
- {
-+ global $kolab_current_tasklist;
-+ $kolab_current_tasklist = null;
-+
- $this->_tasklist = $tasklist;
- $this->_kolab = &$kolab;
- }
-@@ -285,7 +293,9 @@
- */
- function connect($loader = 0)
- {
-- if ($this->_connected) {
-+ global $kolab_current_tasklist;
-+
-+ if ($kolab_current_tasklist == $this->_tasklist) {
- return true;
- }
-
-@@ -294,7 +304,7 @@
- return $result;
- }
-
-- $this->_connected = true;
-+ $kolab_current_tasklist = $this->_tasklist;
-
- return true;
- }
-@@ -379,13 +389,15 @@
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
- * @param integer $completed_date The task's completion date.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- *
- * @return string The ID of the task.
- */
- function _setObject($name, $desc, $start = 0, $due = 0, $priority = 0,
- $estimate = 0.0, $completed = 0, $category = '',
- $alarm = 0, $parent = null, $private = false,
-- $owner = null, $assignee = null, $completed_date = null)
-+ $owner = null, $assignee = null, $completed_date = null,
-+ $recurrence = null)
- {
- if ($due == 0) {
- $alarm = 0;
-@@ -432,13 +444,14 @@
- * @param boolean $private Whether the task is private.
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- *
- * @return string The Nag ID of the new task.
- */
- function add($name, $desc, $start = 0, $due = 0, $priority = 0,
- $completed = 0, $estimate = 0.0, $category = '', $alarm = 0,
- $uid = null, $parent = null, $private = false, $owner = null,
-- $assignee = null)
-+ $assignee = null, $recurrence = null)
- {
- // Usually provided by the generic Driver class
- if ($uid !== null) {
-@@ -453,7 +466,8 @@
-
- return $this->_setObject($name, $desc, $start, $due, $priority,
- $completed, $estimate, $category, $alarm,
-- $parent, $private, $owner, $assignee);
-+ $parent, $private, $owner, $assignee,
-+ $recurrence);
- }
-
- /**
-@@ -474,6 +488,7 @@
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
- * @param integer $completed_date The task's completion date.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- *
- * @return boolean Indicates if the modification was successfull.
- */
-@@ -481,7 +496,7 @@
- $priority = 0, $estimate = 0.0, $completed = 0,
- $category = '', $alarm = 0, $parent = null,
- $private = false, $owner = null, $assignee = null,
-- $completed_date = null)
-+ $completed_date = null, $recurrence = null)
- {
- // Load the object into the kolab driver
- $result = $this->_kolab->loadObject($taskId);
-@@ -492,7 +507,7 @@
- $result = $this->_setObject($name, $desc, $start, $due, $priority,
- $estimate, $completed, $category, $alarm,
- $parent, $private, $owner, $assignee,
-- $completed_date);
-+ $completed_date, $recurrence);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
-@@ -672,7 +687,9 @@
- */
- function connect()
- {
-- if ($this->_connected) {
-+ global $kolab_current_tasklist;
-+
-+ if (isset($this->_store) && $kolab_current_tasklist == $this->_tasklist) {
- return true;
- }
-
-@@ -687,43 +704,6 @@
- }
-
- /**
-- * Split the tasklist name of the id. We use this to make ids
-- * unique across folders.
-- *
-- * @param string $id The ID of the task appended with the tasklist
-- * name.
-- *
-- * @return array The task id and tasklist name
-- */
-- function _splitId($id)
-- {
-- $split = split('@', $id, 2);
-- if (count($split) == 2) {
-- list($id, $tasklist) = $split;
-- } else if (count($split) == 1) {
-- $tasklist = Auth::getAuth();
-- }
-- return array($id, $tasklist);
-- }
--
-- /**
-- * Append the tasklist name to the id. We use this to make ids
-- * unique across folders.
-- *
-- * @param string $id The ID of the task
-- *
-- * @return string The task id appended with the tasklist
-- * name.
-- */
-- function _uniqueId($id)
-- {
-- if ($this->_tasklist == Auth::getAuth()) {
-- return $id;
-- }
-- return $id . '@' . $this->_tasklist;
-- }
--
-- /**
- * Retrieves one task from the store.
- *
- * @param string $taskId The id of the task to retrieve.
-@@ -732,7 +712,10 @@
- */
- function get($taskId)
- {
-- list($taskId, $tasklist) = $this->_splitId($taskId);
-+ $result = $this->connect();
-+ if (is_a($result, 'PEAR_Error')) {
-+ return $result;
-+ }
-
- if ($this->_store->objectUidExists($taskId)) {
- $task = $this->_store->getObject($taskId);
-@@ -751,15 +734,24 @@
- */
- function getByUID($uid)
- {
-- list($taskId, $tasklist) = $this->_splitId($uid);
-+ $tasklists = array_keys(Nag::listTasklists(true, PERMS_READ));
-
-- if ($this->_tasklist != $tasklist) {
-+ foreach ($tasklists as $tasklist) {
- $this->_tasklist = $tasklist;
-- $this->_connected = false;
-- $this->connect();
-+ $result = $this->connect();
-+ if (is_a($result, 'PEAR_Error')) {
-+ return $result;
-+ }
-+
-+ if (!$this->_store->objectUidExists($uid)) {
-+ continue;
-+ }
-+
-+ // Ok, found task
-+ return $this->get($uid);
- }
-
-- return $this->get($taskId);
-+ return PEAR::raiseError(sprintf(_("Task not found: %s"), $uid));
- }
-
- /**
-@@ -780,6 +772,8 @@
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
- * @param integer $completed_date The task's completion date.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
-+ * @param boolean $add Are we adding a new task?
- *
- * @return mixed The id of the task if successful, a PEAR error
- * otherwise
-@@ -788,18 +782,13 @@
- $estimate = 0.0, $completed = 0, $category = '',
- $alarm = 0, $uid = null, $parent = null,
- $private = false, $owner = null, $assignee = null,
-- $completed_date = null)
-+ $completed_date = null, $recurrence = null,
-+ $add = false)
- {
-- if (empty($uid)) {
-- $task_uid = $this->_store->generateUID();
-+ if ($add) {
- $old_uid = null;
- } else {
-- list($task_uid, $tasklist) = $this->_splitId($uid);
-- $old_uid = $task_uid;
-- }
--
-- if ($parent) {
-- list($parent, $dummy) = $this->_splitId($parent);
-+ $old_uid = $uid;
- }
-
- if ($private) {
-@@ -808,8 +797,12 @@
- $sensitivity = 'public';
- }
-
-+ if ($recurrence) {
-+ $recurrence = $recurrence->toHash();
-+ }
-+
- $result = $this->_store->save(array(
-- 'uid' => $task_uid,
-+ 'uid' => $uid,
- 'name' => $name,
- 'body' => $desc,
- 'start' => $start,
-@@ -817,6 +810,7 @@
- 'priority' => $priority,
- 'completed' => $completed,
- 'categories' => $category,
-+ 'recurrence' => $recurrence,
- 'alarm' => $alarm,
- 'parent' => $parent,
- 'sensitivity' => $sensitivity,
-@@ -834,7 +828,7 @@
- return $result;
- }
-
-- return $task_uid;
-+ return $uid;
- }
-
- /**
-@@ -854,6 +848,7 @@
- * @param boolean $private Whether the task is private.
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- *
- * @return mixed The id of the task if successful, a PEAR error
- * otherwise
-@@ -861,11 +856,12 @@
- function add($name, $desc, $start = 0, $due = 0, $priority = 0,
- $estimate = 0.0, $completed = 0, $category = '', $alarm = 0,
- $uid = null, $parent = null, $private = false, $owner = null,
-- $assignee = null)
-+ $assignee = null, $recurrence = null)
- {
- return $this->_setObject($name, $desc, $start, $due, $priority,
- $estimate, $completed, $category, $alarm,
-- null, $parent, $private, $owner, $assignee);
-+ $uid, $parent, $private, $owner, $assignee,
-+ null, $recurrence, true);
- }
-
- /**
-@@ -886,6 +882,7 @@
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
- * @param integer $completed_date The task's completion date.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- *
- * @return mixed The id of the task if successful, a PEAR error
- * otherwise
-@@ -893,12 +890,13 @@
- function modify($taskId, $name, $desc, $start = 0, $due = 0, $priority = 0,
- $estimate = 0.0, $completed = 0, $category = '',
- $alarm = 0, $parent = null, $private = false,
-- $owner = null, $assignee = null, $completed_date = null)
-+ $owner = null, $assignee = null, $completed_date = null,
-+ $recurrence = null)
- {
- $result = $this->_setObject($name, $desc, $start, $due, $priority,
- $estimate, $completed, $category, $alarm,
- $taskId, $parent, $private, $owner, $assignee,
-- $completed_date);
-+ $completed_date, $recurrence);
- if (is_a($result, 'PEAR_Error')) {
- return $result;
- }
-@@ -916,8 +914,6 @@
- */
- function move($taskId, $newTasklist)
- {
-- list($taskId, $tasklist) = $this->_splitId($taskId);
--
- return $this->_store->move($taskId, $newTasklist);
- }
-
-@@ -928,8 +924,6 @@
- */
- function delete($taskId)
- {
-- list($taskId, $tasklist) = $this->_splitId($taskId);
--
- return $this->_store->delete($taskId);
- }
-
-@@ -953,6 +947,11 @@
- */
- function retrieve($completed = 1)
- {
-+ $result = $this->connect();
-+ if (is_a($result, 'PEAR_Error')) {
-+ return $result;
-+ }
-+
- $dict = array();
- $tasks = new Nag_Task();
-
-@@ -960,13 +959,14 @@
- if (is_a($task_list, 'PEAR_Error')) {
- return $task_list;
- }
-+
-
- if (empty($task_list)) {
- return $tasks;
- }
-
- foreach ($task_list as $task) {
-- $tuid = $this->_uniqueId($task['uid']);
-+ $tuid = $task['uid'];
- $t = &new Nag_Task($this->_buildTask($task));
- $complete = $t->completed;
- if (empty($t->start)) {
-@@ -1014,10 +1014,10 @@
- function _buildTask($task)
- {
- $task['tasklist_id'] = $this->_tasklist;
-- $task['task_id'] = $this->_uniqueId($task['uid']);
-+ $task['task_id'] = $task['uid'];
-
- if (!empty($task['parent'])) {
-- $task['parent'] = $this->_uniqueId($task['parent']);
-+ $task['parent'] = $task['parent'];
- }
-
- $task['category'] = $task['categories'];
-@@ -1032,6 +1032,13 @@
- $task['private'] = true;
- }
- unset($task['sensitivity']);
-+
-+ if (isset($task['recurrence']) && isset($task['due'])) {
-+ require_once NAG_BASE . '/lib/Recurrence.php';
-+ $recurrence = new Nag_Recurrence($task['due']);
-+ $recurrence->fromHash($task['recurrence']);
-+ $task['recurrence'] = $recurrence;
-+ }
-
- $share = &$GLOBALS['nag_shares']->getShare($this->_tasklist);
- $task['owner'] = $share->get('owner');
-@@ -1048,6 +1055,11 @@
- */
- function listAlarms($date)
- {
-+ $result = $this->connect();
-+ if (is_a($result, 'PEAR_Error')) {
-+ return $result;
-+ }
-+
- $task_list = $this->_store->getObjects();
- if (is_a($task_list, 'PEAR_Error')) {
- return $task_list;
-@@ -1059,7 +1071,7 @@
-
- $tasks = array();
- foreach ($task_list as $task) {
-- $tuid = $this->_uniqueId($task['uid']);
-+ $tuid = $task['uid'];
- $t = new Nag_Task($this->_buildTask($task));
- if ($t->alarm && $t->due &&
- $t->due - $t->alarm * 60 < $date) {
-@@ -1079,7 +1091,10 @@
- */
- function getChildren($parentId)
- {
-- list($parentId, $tasklist) = $this->_splitId($parentId);
-+ $result = $this->connect();
-+ if (is_a($result, 'PEAR_Error')) {
-+ return $result;
-+ }
-
- $task_list = $this->_store->getObjects();
- if (is_a($task_list, 'PEAR_Error')) {
-diff -r f7b1e151bdb5 nag/lib/Driver/sql.php
---- a/nag/lib/Driver/sql.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/lib/Driver/sql.php Wed Aug 13 21:37:23 2008 +0200
-@@ -158,13 +158,14 @@
- * @param boolean $private Whether the task is private.
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- *
- * @return string The Nag ID of the new task.
- */
- function _add($name, $desc, $start = 0, $due = 0, $priority = 0,
- $estimate = 0.0, $completed = 0, $category = '', $alarm = 0,
- $uid = null, $parent = '', $private = false, $owner = null,
-- $assignee = null)
-+ $assignee = null, $recurrence = null)
- {
- $taskId = md5(uniqid(mt_rand(), true));
- if ($uid === null) {
-@@ -229,12 +230,13 @@
- * @param string $owner The owner of the event.
- * @param string $assignee The assignee of the event.
- * @param integer $completed_date The task's completion date.
-+ * @param Nag_Recurrence $recurrence Task recurrence.
- */
- function _modify($taskId, $name, $desc, $start = 0, $due = 0,
- $priority = 0, $estimate = 0.0, $completed = 0,
- $category = '', $alarm = 0, $parent = '',
- $private = false, $owner = null, $assignee = null,
-- $completed_date = null)
-+ $completed_date = null, $recurrence = null)
- {
- $query = sprintf('UPDATE %s SET' .
- ' task_creator = ?, ' .
-diff -r f7b1e151bdb5 nag/lib/Forms/task.php
---- a/nag/lib/Forms/task.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/lib/Forms/task.php Wed Aug 13 21:37:23 2008 +0200
-@@ -87,6 +87,7 @@
-
- $this->addVariable(_("Private?"), 'private', 'boolean', false);
- $this->addVariable(_("Due By"), 'due', 'nag_due', false);
-+
- $this->addVariable(_("Delay Start Until"), 'start', 'nag_start', false);
- $this->addVariable(_("Alarm"), 'alarm', 'nag_alarm', false);
-
-@@ -96,6 +97,9 @@
- $this->addVariable(_("Estimated Time"), 'estimate', 'number', false);
- $this->addVariable(_("Completed?"), 'completed', 'boolean', false);
- $this->addVariable(_("Description"), 'desc', 'longtext', false);
-+
-+ $this->addVariable(_("Recurrence"), 'recurrence', 'nag_recurrence', false, false, false);
-+ $this->addVariable(_("Recur Until"), 'recur_end', 'nag_recur_end', false, false, false);
-
- $buttons = array(_("Save"));
- if ($delete) {
-@@ -214,6 +218,150 @@
- }
-
- /**
-+ * The Horde_Form_Type_nag_recurrence class provides a form field for editing
-+ * task recurrences.
-+ *
-+ * @author Gunnar Wrobel <p@rdus.de>
-+ * @since Nag 2.2
-+ * @package Nag
-+ */
-+class Horde_Form_Type_nag_recurrence extends Horde_Form_Type {
-+
-+ function getInfo(&$vars, &$var, &$info)
-+ {
-+ $recurrence = $vars->get('recurrence');
-+ if ($recurrence) {
-+ $info = $recurrence;
-+ return;
-+ }
-+
-+ // Recurrence.
-+ $recur = $vars->get('recur');
-+ if ($recur !== null && $recur !== '') {
-+ require_once NAG_BASE . '/lib/Recurrence.php';
-+ $recurrence = new Nag_Recurrence(time());
-+
-+ $recurrence->setRecurType($recur);
-+ switch ($recur) {
-+ case NAG_RECUR_DAILY:
-+ $recurrence->setRecurInterval($vars->get('recur_daily_interval', 1));
-+ break;
-+
-+ case NAG_RECUR_WEEKLY:
-+ $weekly = $vars->get('weekly');
-+ $weekdays = 0;
-+ if (is_array($weekly)) {
-+ foreach ($weekly as $day) {
-+ $weekdays |= $day;
-+ }
-+ }
-+
-+ if ($weekdays == 0) {
-+ // Sunday starts at 0.
-+ switch ($this->start->dayOfWeek()) {
-+ case 0: $weekdays |= HORDE_DATE_MASK_SUNDAY; break;
-+ case 1: $weekdays |= HORDE_DATE_MASK_MONDAY; break;
-+ case 2: $weekdays |= HORDE_DATE_MASK_TUESDAY; break;
-+ case 3: $weekdays |= HORDE_DATE_MASK_WEDNESDAY; break;
-+ case 4: $weekdays |= HORDE_DATE_MASK_THURSDAY; break;
-+ case 5: $weekdays |= HORDE_DATE_MASK_FRIDAY; break;
-+ case 6: $weekdays |= HORDE_DATE_MASK_SATURDAY; break;
-+ }
-+ }
-+
-+ $recurrence->setRecurInterval($vars->get('recur_weekly_interval', 1));
-+ $recurrence->setRecurOnDay($weekdays);
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_DATE:
-+ $recurrence->setRecurInterval($vars->get('recur_day_of_month_interval', 1));
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_WEEKDAY:
-+ $recurrence->setRecurInterval($vars->get('recur_week_of_month_interval', 1));
-+ break;
-+
-+ case NAG_RECUR_YEARLY_DATE:
-+ $recurrence->setRecurInterval($vars->get('recur_yearly_interval', 1));
-+ break;
-+
-+ case NAG_RECUR_YEARLY_DAY:
-+ $recurrence->setRecurInterval($vars->get('recur_yearly_day_interval', 1));
-+ break;
-+
-+ case NAG_RECUR_YEARLY_WEEKDAY:
-+ $recurrence->setRecurInterval($vars->get('recur_yearly_weekday_interval', 1));
-+ break;
-+ }
-+ $info = $recurrence->toHash();
-+ } else {
-+ $info = array();
-+ }
-+ }
-+
-+ function isValid(&$var, &$vars, $value, &$message)
-+ {
-+ return true;
-+ }
-+
-+}
-+
-+/**
-+ * The Horde_Form_Type_nag_recur_end class provides a form field for editing
-+ * task recurrence ends.
-+ *
-+ * @author Gunnar Wrobel <p@rdus.de>
-+ * @since Nag 2.2
-+ * @package Nag
-+ */
-+class Horde_Form_Type_nag_recur_end extends Horde_Form_Type {
-+
-+ function getInfo(&$vars, &$var, &$info)
-+ {
-+ $r = $vars->get('recurrence');
-+ if ($r) {
-+ $info = array('range' => $r['range'],
-+ 'range-type' => $r['range-type']);
-+ return;
-+ }
-+
-+ // Recurrence.
-+ $recur = $vars->get('recur');
-+ if ($recur !== null && $recur !== '') {
-+ require_once NAG_BASE . '/lib/Recurrence.php';
-+ $recurrence = new Nag_Recurrence(time());
-+ $recurrence->setRecurType(NAG_RECUR_DAILY);
-+ if ($vars->get('recur_enddate_type') == 'date') {
-+ $recur_enddate = $vars->get('recur_enddate');
-+ $recurrence->setRecurEnd(new Horde_Date(
-+ array('hour' => 1,
-+ 'min' => 1,
-+ 'sec' => 1,
-+ 'month' => $recur_enddate['month'],
-+ 'mday' => $recur_enddate['day'],
-+ 'year' => $recur_enddate['year'])));
-+ } elseif ($vars->get('recur_enddate_type') == 'count') {
-+ $recurrence->setRecurCount($vars->get('recur_count'));
-+ } elseif ($vars->get('recur_enddate_type') == 'none') {
-+ $recurrence->setRecurCount(0);
-+ $recurrence->setRecurEnd(null);
-+ }
-+ $r = $recurrence->toHash();
-+ $info = array('range' => $r['range'],
-+ 'range-type' => $r['range-type']);
-+ } else {
-+ $info = array();
-+ }
-+ }
-+
-+ function isValid(&$var, &$vars, $value, &$message)
-+ {
-+ return true;
-+ }
-+
-+}
-+
-+/**
- * The Horde_Form_Type_nag_start class provides a form field for editing
- * task delayed start dates.
- *
-diff -r f7b1e151bdb5 nag/lib/Recurrence.php
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/nag/lib/Recurrence.php Wed Aug 13 21:37:23 2008 +0200
-@@ -0,0 +1,1469 @@
-+<?php
-+/**
-+ * This file contains the Nag_Recurrence class and according constants.
-+ *
-+ * $Horde: nag/lib/Recurrence.php,v 1.1 2008/07/13 12:36:03 jan Exp $
-+ *
-+ * Copyright 2007-2008 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.
-+ *
-+ * @since Horde 3.2
-+ * @package Horde_Date
-+ */
-+
-+/** Horde_Date */
-+require_once 'Horde/Date.php';
-+
-+/** Date_Calc */
-+require_once 'Date/Calc.php';
-+
-+/** No recurrence. */
-+define('NAG_RECUR_NONE', 0);
-+/** Recurs daily. */
-+define('NAG_RECUR_DAILY', 1);
-+/** Recurs weekly. */
-+define('NAG_RECUR_WEEKLY', 2);
-+/** Recurs monthly on the same date. */
-+define('NAG_RECUR_MONTHLY_DATE', 3);
-+/** Recurs monthly on the same week day. */
-+define('NAG_RECUR_MONTHLY_WEEKDAY', 4);
-+/** Recurs yearly on the same date. */
-+define('NAG_RECUR_YEARLY_DATE', 5);
-+/** Recurs yearly on the same day of the year. */
-+define('NAG_RECUR_YEARLY_DAY', 6);
-+/** Recurs yearly on the same week day. */
-+define('NAG_RECUR_YEARLY_WEEKDAY', 7);
-+
-+/**
-+ * The Nag_Recurrence class implements algorithms for calculating
-+ * recurrences of events, including several recurrence types, intervals,
-+ * exceptions, and conversion from and to vCalendar and iCalendar recurrence
-+ * rules.
-+ *
-+ * All methods expecting dates as parameters accept all values that the
-+ * Horde_Date constructor accepts, i.e. a timestamp, another Horde_Date
-+ * object, an ISO time string or a hash.
-+ *
-+ * @author Jan Schneider <jan@horde.org>
-+ * @since Horde 3.2
-+ * @package Horde_Date
-+ */
-+class Nag_Recurrence {
-+
-+ /**
-+ * The start time of the event.
-+ *
-+ * @var Horde_Date
-+ */
-+ var $start;
-+
-+ /**
-+ * The end date of the recurrence interval.
-+ *
-+ * @var Horde_Date
-+ */
-+ var $recurEnd = null;
-+
-+ /**
-+ * The number of recurrences.
-+ *
-+ * @var integer
-+ */
-+ var $recurCount = null;
-+
-+ /**
-+ * The type of recurrence this event follows. NAG_RECUR_* constant.
-+ *
-+ * @var integer
-+ */
-+ var $recurType = NAG_RECUR_NONE;
-+
-+ /**
-+ * The length of time between recurrences. The time unit depends on the
-+ * recurrence type.
-+ *
-+ * @var integer
-+ */
-+ var $recurInterval = 1;
-+
-+ /**
-+ * Any additional recurrence data.
-+ *
-+ * @var integer
-+ */
-+ var $recurData = null;
-+
-+ /**
-+ * All the exceptions from recurrence for this event.
-+ *
-+ * @var array
-+ */
-+ var $exceptions = array();
-+
-+ /**
-+ * All the dates this recurrence has been marked as completed.
-+ *
-+ * @var array
-+ */
-+ var $completions = array();
-+
-+ /**
-+ * Constructor.
-+ *
-+ * @param Horde_Date $start Start of the recurring event.
-+ */
-+ function Nag_Recurrence($start)
-+ {
-+ $this->start = new Horde_Date($start);
-+ }
-+
-+ /**
-+ * Checks if this event recurs on a given day of the week.
-+ *
-+ * @param integer $dayMask A mask consisting of HORDE_DATE_MASK_*
-+ * constants specifying the day(s) to check.
-+ *
-+ * @return boolean True if this event recurs on the given day(s).
-+ */
-+ function recurOnDay($dayMask)
-+ {
-+ return ($this->recurData & $dayMask);
-+ }
-+
-+ /**
-+ * Specifies the days this event recurs on.
-+ *
-+ * @param integer $dayMask A mask consisting of HORDE_DATE_MASK_*
-+ * constants specifying the day(s) to recur on.
-+ */
-+ function setRecurOnDay($dayMask)
-+ {
-+ $this->recurData = $dayMask;
-+ }
-+
-+ /**
-+ * Returns the days this event recurs on.
-+ *
-+ * @return integer A mask consisting of HORDE_DATE_MASK_* constants
-+ * specifying the day(s) this event recurs on.
-+ */
-+ function getRecurOnDays()
-+ {
-+ return $this->recurData;
-+ }
-+
-+ /**
-+ * Returns whether this event has a specific recurrence type.
-+ *
-+ * @param integer $recurrence NAG_RECUR_* constant of the
-+ * recurrence type to check for.
-+ *
-+ * @return boolean True if the event has the specified recurrence type.
-+ */
-+ function hasRecurType($recurrence)
-+ {
-+ return ($recurrence == $this->recurType);
-+ }
-+
-+ /**
-+ * Sets a recurrence type for this event.
-+ *
-+ * @param integer $recurrence A NAG_RECUR_* constant.
-+ */
-+ function setRecurType($recurrence)
-+ {
-+ $this->recurType = $recurrence;
-+ }
-+
-+ /**
-+ * Returns recurrence type of this event.
-+ *
-+ * @return integer A NAG_RECUR_* constant.
-+ */
-+ function getRecurType()
-+ {
-+ return $this->recurType;
-+ }
-+
-+ /**
-+ * Returns a description of this event's recurring type.
-+ *
-+ * @return string Human readable recurring type.
-+ */
-+ function getRecurName()
-+ {
-+ switch ($this->getRecurType()) {
-+ case NAG_RECUR_NONE: return _("No recurrence");
-+ case NAG_RECUR_DAILY: return _("Daily");
-+ case NAG_RECUR_WEEKLY: return _("Weekly");
-+ case NAG_RECUR_MONTHLY_DATE:
-+ case NAG_RECUR_MONTHLY_WEEKDAY: return _("Monthly");
-+ case NAG_RECUR_YEARLY_DATE:
-+ case NAG_RECUR_YEARLY_DAY:
-+ case NAG_RECUR_YEARLY_WEEKDAY: return _("Yearly");
-+ }
-+ }
-+
-+ /**
-+ * Sets the length of time between recurrences of this event.
-+ *
-+ * @param integer $interval The time between recurrences.
-+ */
-+ function setRecurInterval($interval)
-+ {
-+ if ($interval > 0) {
-+ $this->recurInterval = $interval;
-+ }
-+ }
-+
-+ /**
-+ * Retrieves the length of time between recurrences of this event.
-+ *
-+ * @return integer The number of seconds between recurrences.
-+ */
-+ function getRecurInterval()
-+ {
-+ return $this->recurInterval;
-+ }
-+
-+ /**
-+ * Sets the number of recurrences of this event.
-+ *
-+ * @param integer $count The number of recurrences.
-+ */
-+ function setRecurCount($count)
-+ {
-+ if ($count > 0) {
-+ $this->recurCount = (int)$count;
-+ // Recurrence counts and end dates are mutually exclusive.
-+ $this->recurEnd = null;
-+ } else {
-+ $this->recurCount = null;
-+ }
-+ }
-+
-+ /**
-+ * Retrieves the number of recurrences of this event.
-+ *
-+ * @return integer The number recurrences.
-+ */
-+ function getRecurCount()
-+ {
-+ return $this->recurCount;
-+ }
-+
-+ /**
-+ * Returns whether this event has a recurrence with a fixed count.
-+ *
-+ * @return boolean True if this recurrence has a fixed count.
-+ */
-+ function hasRecurCount()
-+ {
-+ return isset($this->recurCount);
-+ }
-+
-+ /**
-+ * Sets the start date of the recurrence interval.
-+ *
-+ * @param Horde_Date $start The recurrence start.
-+ */
-+ function setRecurStart($start)
-+ {
-+ $this->start = new Horde_Date($start);
-+ }
-+
-+ /**
-+ * Retrieves the start date of the recurrence interval.
-+ *
-+ * @return Horde_Date The recurrence start.
-+ */
-+ function getRecurStart()
-+ {
-+ return $this->start;
-+ }
-+
-+ /**
-+ * Sets the end date of the recurrence interval.
-+ *
-+ * @param Horde_Date $end The recurrence end.
-+ */
-+ function setRecurEnd($end)
-+ {
-+ if (!empty($end)) {
-+ // Recurrence counts and end dates are mutually exclusive.
-+ $this->recurCount = null;
-+ }
-+ $this->recurEnd = new Horde_Date($end);
-+ }
-+
-+ /**
-+ * Retrieves the end date of the recurrence interval.
-+ *
-+ * @return Horde_Date The recurrence end.
-+ */
-+ function getRecurEnd()
-+ {
-+ return $this->recurEnd;
-+ }
-+
-+ /**
-+ * Returns whether this event has a recurrence end.
-+ *
-+ * @return boolean True if this recurrence ends.
-+ */
-+ function hasRecurEnd()
-+ {
-+ return isset($this->recurEnd) && isset($this->recurEnd->year) &&
-+ $this->recurEnd->year != 9999;
-+ }
-+
-+ /**
-+ * Finds the next recurrence of this event that's after $afterDate.
-+ *
-+ * @param Horde_Date $afterDate Return events after this date.
-+ *
-+ * @return Horde_Date|boolean The date of the next recurrence or false
-+ * if the event does not recur after
-+ * $afterDate.
-+ */
-+ function nextRecurrence($afterDate)
-+ {
-+ $after = new Horde_Date($afterDate);
-+ $after->correct();
-+
-+ if ($this->start->compareDateTime($after) >= 0) {
-+ return new Horde_Date($this->start);
-+ }
-+
-+ if ($this->recurInterval == 0) {
-+ return false;
-+ }
-+
-+ switch ($this->getRecurType()) {
-+ case NAG_RECUR_DAILY:
-+ $diff = Date_Calc::dateDiff($this->start->mday, $this->start->month, $this->start->year, $after->mday, $after->month, $after->year);
-+ $recur = ceil($diff / $this->recurInterval);
-+ if ($this->recurCount && $recur >= $this->recurCount) {
-+ return false;
-+ }
-+ $recur *= $this->recurInterval;
-+ $next = new Horde_Date($this->start);
-+ list($next->mday, $next->month, $next->year) = explode('/', Date_Calc::daysToDate(Date_Calc::dateToDays($next->mday, $next->month, $next->year) + $recur, '%e/%m/%Y'));
-+ if ((!$this->hasRecurEnd() ||
-+ $next->compareDateTime($this->recurEnd) <= 0) &&
-+ $next->compareDateTime($after) >= 0) {
-+ return new Horde_Date($next);
-+ }
-+ break;
-+
-+ case NAG_RECUR_WEEKLY:
-+ if (empty($this->recurData)) {
-+ return false;
-+ }
-+
-+ list($start_week->mday, $start_week->month, $start_week->year) = explode('/', Date_Calc::beginOfWeek($this->start->mday, $this->start->month, $this->start->year, '%e/%m/%Y'));
-+ $start_week->hour = $this->start->hour;
-+ $start_week->min = $this->start->min;
-+ $start_week->sec = $this->start->sec;
-+ list($after_week->mday, $after_week->month, $after_week->year) = explode('/', Date_Calc::beginOfWeek($after->mday, $after->month, $after->year, '%e/%m/%Y'));
-+ $after_week_end = new Horde_Date($after_week);
-+ $after_week_end->mday += 7;
-+ $after_week_end->correct();
-+
-+ $diff = Date_Calc::dateDiff($start_week->mday, $start_week->month, $start_week->year,
-+ $after_week->mday, $after_week->month, $after_week->year);
-+ $recur = $diff + ($diff % ($this->recurInterval * 7));
-+ if ($this->recurCount &&
-+ ceil($recur / 7) / $this->recurInterval >= $this->recurCount) {
-+ return false;
-+ }
-+ $next = $start_week;
-+ list($next->mday, $next->month, $next->year) = explode('/', Date_Calc::daysToDate(Date_Calc::dateToDays($next->mday, $next->month, $next->year) + $recur, '%e/%m/%Y'));
-+ $next = new Horde_Date($next);
-+ while ($next->compareDateTime($after) < 0 &&
-+ $next->compareDateTime($after_week_end) < 0) {
-+ ++$next->mday;
-+ $next->correct();
-+ }
-+ if (!$this->hasRecurEnd() ||
-+ $next->compareDateTime($this->recurEnd) <= 0) {
-+ if ($next->compareDateTime($after_week_end) >= 0) {
-+ return $this->nextRecurrence($after_week_end);
-+ }
-+ while (!$this->recurOnDay((int)pow(2, $next->dayOfWeek())) &&
-+ $next->compareDateTime($after_week_end) < 0) {
-+ ++$next->mday;
-+ $next->correct();
-+ }
-+ if (!$this->hasRecurEnd() ||
-+ $next->compareDateTime($this->recurEnd) <= 0) {
-+ if ($next->compareDateTime($after_week_end) >= 0) {
-+ return $this->nextRecurrence($after_week_end);
-+ } else {
-+ return $next;
-+ }
-+ }
-+ }
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_DATE:
-+ $start = new Horde_Date($this->start);
-+ if ($after->compareDateTime($start) < 0) {
-+ $after = $start;
-+ }
-+
-+ // If we're starting past this month's recurrence of the event,
-+ // look in the next month on the day the event recurs.
-+ if ($after->mday > $start->mday) {
-+ ++$after->month;
-+ $after->mday = $start->mday;
-+ $after->correct();
-+ }
-+
-+ // Adjust $start to be the first match.
-+ $offset = ($after->month - $start->month) + ($after->year - $start->year) * 12;
-+ $offset = floor(($offset + $this->recurInterval - 1) / $this->recurInterval) * $this->recurInterval;
-+
-+ if ($this->recurCount &&
-+ ($offset / $this->recurInterval) >= $this->recurCount) {
-+ return false;
-+ }
-+ $start->month += $offset;
-+ $count = $offset / $this->recurInterval;
-+
-+ do {
-+ if ($this->recurCount &&
-+ $count++ >= $this->recurCount) {
-+ return false;
-+ }
-+
-+ // Don't correct for day overflow; we just skip February 30th,
-+ // for example.
-+ $start->correct(HORDE_DATE_MASK_MONTH);
-+
-+ // Bail if we've gone past the end of recurrence.
-+ if ($this->hasRecurEnd() &&
-+ $this->recurEnd->compareDateTime($start) < 0) {
-+ return false;
-+ }
-+ if ($start->isValid()) {
-+ return $start;
-+ }
-+
-+ // If the interval is 12, and the date isn't valid, then we
-+ // need to see if February 29th is an option. If not, then the
-+ // event will _never_ recur, and we need to stop checking to
-+ // avoid an infinite loop.
-+ if ($this->recurInterval == 12 && ($start->month != 2 || $start->mday > 29)) {
-+ return false;
-+ }
-+
-+ // Add the recurrence interval.
-+ $start->month += $this->recurInterval;
-+ } while (true);
-+
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_WEEKDAY:
-+ // Start with the start date of the event.
-+ $estart = new Horde_Date($this->start);
-+
-+ // What day of the week, and week of the month, do we recur on?
-+ $nth = ceil($this->start->mday / 7);
-+ $weekday = $estart->dayOfWeek();
-+
-+ // Adjust $estart to be the first candidate.
-+ $offset = ($after->month - $estart->month) + ($after->year - $estart->year) * 12;
-+ $offset = floor(($offset + $this->recurInterval - 1) / $this->recurInterval) * $this->recurInterval;
-+
-+ // Adjust our working date until it's after $after.
-+ $estart->month += $offset - $this->recurInterval;
-+
-+ $count = $offset / $this->recurInterval;
-+ do {
-+ if ($this->recurCount &&
-+ $count++ >= $this->recurCount) {
-+ return false;
-+ }
-+
-+ $estart->month += $this->recurInterval;
-+ $estart->correct();
-+
-+ $next = new Horde_Date($estart);
-+ $next->setNthWeekday($weekday, $nth);
-+
-+ if ($next->compareDateTime($after) < 0) {
-+ // We haven't made it past $after yet, try again.
-+ continue;
-+ }
-+ if ($this->hasRecurEnd() &&
-+ $next->compareDateTime($this->recurEnd) > 0) {
-+ // We've gone past the end of recurrence; we can give up
-+ // now.
-+ return false;
-+ }
-+
-+ // We have a candidate to return.
-+ break;
-+ } while (true);
-+
-+ return $next;
-+
-+ case NAG_RECUR_YEARLY_DATE:
-+ // Start with the start date of the event.
-+ $estart = new Horde_Date($this->start);
-+
-+ if ($after->month > $estart->month ||
-+ ($after->month == $estart->month && $after->mday > $estart->mday)) {
-+ ++$after->year;
-+ $after->month = $estart->month;
-+ $after->mday = $estart->mday;
-+ }
-+
-+ // Seperate case here for February 29th
-+ if ($estart->month == 2 && $estart->mday == 29) {
-+ while (!Horde_Date::isLeapYear($after->year)) {
-+ ++$after->year;
-+ }
-+ }
-+
-+ // Adjust $estart to be the first candidate.
-+ $offset = $after->year - $estart->year;
-+ if ($offset > 0) {
-+ $offset = floor(($offset + $this->recurInterval - 1) / $this->recurInterval) * $this->recurInterval;
-+ $estart->year += $offset;
-+ }
-+
-+ // We've gone past the end of recurrence; give up.
-+ if ($this->recurCount &&
-+ $offset >= $this->recurCount) {
-+ return false;
-+ }
-+ if ($this->hasRecurEnd() &&
-+ $this->recurEnd->compareDateTime($estart) < 0) {
-+ return false;
-+ }
-+
-+ return $estart;
-+
-+ case NAG_RECUR_YEARLY_DAY:
-+ // Check count first.
-+ $dayofyear = $this->start->dayOfYear();
-+ $count = ($after->year - $this->start->year) / $this->recurInterval + 1;
-+ if ($this->recurCount &&
-+ ($count > $this->recurCount ||
-+ ($count == $this->recurCount &&
-+ $after->dayOfYear() > $dayofyear))) {
-+ return false;
-+ }
-+
-+ // Start with a rough interval.
-+ $estart = new Horde_Date($this->start);
-+ $estart->year += floor($count - 1) * $this->recurInterval;
-+
-+ // Now add the difference to the required day of year.
-+ $estart->mday += $dayofyear - $estart->dayOfYear();
-+ $estart->correct();
-+
-+ // Add an interval if the estimation was wrong.
-+ if ($estart->compareDate($after) < 0) {
-+ $estart->year += $this->recurInterval;
-+ $estart->mday += $dayofyear - $estart->dayOfYear();
-+ $estart->correct();
-+ }
-+
-+ // We've gone past the end of recurrence; give up.
-+ if ($this->hasRecurEnd() &&
-+ $this->recurEnd->compareDateTime($estart) < 0) {
-+ return false;
-+ }
-+
-+ return $estart;
-+
-+ case NAG_RECUR_YEARLY_WEEKDAY:
-+ // Start with the start date of the event.
-+ $estart = new Horde_Date($this->start);
-+
-+ // What day of the week, and week of the month, do we recur on?
-+ $nth = ceil($this->start->mday / 7);
-+ $weekday = $estart->dayOfWeek();
-+
-+ // Adjust $estart to be the first candidate.
-+ $offset = floor(($after->year - $estart->year + $this->recurInterval - 1) / $this->recurInterval) * $this->recurInterval;
-+
-+ // Adjust our working date until it's after $after.
-+ $estart->year += $offset - $this->recurInterval;
-+
-+ $count = $offset / $this->recurInterval;
-+ do {
-+ if ($this->recurCount &&
-+ $count++ >= $this->recurCount) {
-+ return false;
-+ }
-+
-+ $estart->year += $this->recurInterval;
-+ $estart->correct();
-+
-+ $next = new Horde_Date($estart);
-+ $next->setNthWeekday($weekday, $nth);
-+
-+ if ($next->compareDateTime($after) < 0) {
-+ // We haven't made it past $after yet, try again.
-+ continue;
-+ }
-+ if ($this->hasRecurEnd() &&
-+ $next->compareDateTime($this->recurEnd) > 0) {
-+ // We've gone past the end of recurrence; we can give up
-+ // now.
-+ return false;
-+ }
-+
-+ // We have a candidate to return.
-+ break;
-+ } while (true);
-+
-+ return $next;
-+ }
-+
-+ // We didn't find anything, the recurType was bad, or something else
-+ // went wrong - return false.
-+ return false;
-+ }
-+
-+ /**
-+ * Returns whether this event has any date that matches the recurrence
-+ * rules and is not an exception.
-+ *
-+ * @return boolean True if an active recurrence exists.
-+ */
-+ function hasActiveRecurrence()
-+ {
-+ if (!$this->hasRecurEnd()) {
-+ return true;
-+ }
-+
-+ $next = $this->nextRecurrence(new Horde_Date($this->start));
-+ while (is_object($next)) {
-+ if (!$this->hasException($next->year, $next->month, $next->mday) &&
-+ !$this->hasCompletion($next->year, $next->month, $next->mday)) {
-+ return true;
-+ }
-+
-+ $next = $this->nextRecurrence(array('year' => $next->year,
-+ 'month' => $next->month,
-+ 'mday' => $next->mday + 1,
-+ 'hour' => $next->hour,
-+ 'min' => $next->min,
-+ 'sec' => $next->sec));
-+ }
-+
-+ return false;
-+ }
-+
-+ /**
-+ * Returns the next active recurrence.
-+ *
-+ * @param Horde_Date $afterDate Return events after this date.
-+ *
-+ * @return Horde_Date|boolean The date of the next active
-+ * recurrence or false if the event
-+ * has no active recurrence after
-+ * $afterDate.
-+ */
-+ function nextActiveRecurrence($afterDate)
-+ {
-+ $next = $this->nextRecurrence($afterDate);
-+ while (is_object($next)) {
-+ if (!$this->hasException($next->year, $next->month, $next->mday) &&
-+ !$this->hasCompletion($next->year, $next->month, $next->mday)) {
-+ return $next;
-+ }
-+ $next->mday++;
-+ $next = $this->nextRecurrence($next);
-+ }
-+
-+ return false;
-+ }
-+
-+ /**
-+ * Adds an exception to a recurring event.
-+ *
-+ * @param integer $year The year of the execption.
-+ * @param integer $month The month of the execption.
-+ * @param integer $mday The day of the month of the exception.
-+ */
-+ function addException($year, $month, $mday)
-+ {
-+ $this->exceptions[] = sprintf('%04d%02d%02d', $year, $month, $mday);
-+ }
-+
-+ /**
-+ * Deletes an exception from a recurring event.
-+ *
-+ * @param integer $year The year of the execption.
-+ * @param integer $month The month of the execption.
-+ * @param integer $mday The day of the month of the exception.
-+ */
-+ function deleteException($year, $month, $mday)
-+ {
-+ $key = array_search(sprintf('%04d%02d%02d', $year, $month, $mday), $this->exceptions);
-+ if ($key !== false) {
-+ unset($this->exceptions[$key]);
-+ }
-+ }
-+
-+ /**
-+ * Checks if an exception exists for a given reccurence of an event.
-+ *
-+ * @param integer $year The year of the reucrance.
-+ * @param integer $month The month of the reucrance.
-+ * @param integer $mday The day of the month of the reucrance.
-+ *
-+ * @return boolean True if an exception exists for the given date.
-+ */
-+ function hasException($year, $month, $mday)
-+ {
-+ return in_array(sprintf('%04d%02d%02d', $year, $month, $mday),
-+ $this->getExceptions());
-+ }
-+
-+ /**
-+ * Retrieves all the exceptions for this event.
-+ *
-+ * @return array Array containing the dates of all the exceptions in
-+ * YYYYMMDD form.
-+ */
-+ function getExceptions()
-+ {
-+ return $this->exceptions;
-+ }
-+
-+ /**
-+ * Adds an completion to a recurring event.
-+ *
-+ * @param integer $year The year of the execption.
-+ * @param integer $month The month of the execption.
-+ * @param integer $mday The day of the month of the completion.
-+ */
-+ function addCompletion($year, $month, $mday)
-+ {
-+ $this->completions[] = sprintf('%04d%02d%02d', $year, $month, $mday);
-+ }
-+
-+ /**
-+ * Deletes an completion from a recurring event.
-+ *
-+ * @param integer $year The year of the execption.
-+ * @param integer $month The month of the execption.
-+ * @param integer $mday The day of the month of the completion.
-+ */
-+ function deleteCompletion($year, $month, $mday)
-+ {
-+ $key = array_search(sprintf('%04d%02d%02d', $year, $month, $mday), $this->completions);
-+ if ($key !== false) {
-+ unset($this->completions[$key]);
-+ }
-+ }
-+
-+ /**
-+ * Checks if a completion exists for a given reccurence of an event.
-+ *
-+ * @param integer $year The year of the reucrance.
-+ * @param integer $month The month of the recurrance.
-+ * @param integer $mday The day of the month of the recurrance.
-+ *
-+ * @return boolean True if an completion exists for the given date.
-+ */
-+ function hasCompletion($year, $month, $mday)
-+ {
-+ return in_array(sprintf('%04d%02d%02d', $year, $month, $mday),
-+ $this->getCompletions());
-+ }
-+
-+ /**
-+ * Retrieves all the completions for this event.
-+ *
-+ * @return array Array containing the dates of all the completions in
-+ * YYYYMMDD form.
-+ */
-+ function getCompletions()
-+ {
-+ return $this->completions;
-+ }
-+
-+ /**
-+ * Parses a vCalendar 1.0 recurrence rule.
-+ *
-+ * @link http://www.imc.org/pdi/vcal-10.txt
-+ * @link http://www.shuchow.com/vCalAddendum.html
-+ *
-+ * @param string $rrule A vCalendar 1.0 conform RRULE value.
-+ */
-+ function fromRRule10($rrule)
-+ {
-+ if (!$rrule) {
-+ return;
-+ }
-+
-+ if (!preg_match('/([A-Z]+)(\d+)?(.*)/', $rrule, $matches)) {
-+ // No recurrence data - event does not recur.
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ }
-+
-+ // Always default the recurInterval to 1.
-+ $this->setRecurInterval(!empty($matches[2]) ? $matches[2] : 1);
-+
-+ $remainder = trim($matches[3]);
-+
-+ switch ($matches[1]) {
-+ case 'D':
-+ $this->setRecurType(NAG_RECUR_DAILY);
-+ break;
-+
-+ case 'W':
-+ $this->setRecurType(NAG_RECUR_WEEKLY);
-+ if (!empty($remainder)) {
-+ $maskdays = array('SU' => HORDE_DATE_MASK_SUNDAY,
-+ 'MO' => HORDE_DATE_MASK_MONDAY,
-+ 'TU' => HORDE_DATE_MASK_TUESDAY,
-+ 'WE' => HORDE_DATE_MASK_WEDNESDAY,
-+ 'TH' => HORDE_DATE_MASK_THURSDAY,
-+ 'FR' => HORDE_DATE_MASK_FRIDAY,
-+ 'SA' => HORDE_DATE_MASK_SATURDAY);
-+ $mask = 0;
-+ while (preg_match('/^ ?[A-Z]{2} ?/', $remainder, $matches)) {
-+ $day = trim($matches[0]);
-+ $remainder = substr($remainder, strlen($matches[0]));
-+ $mask |= $maskdays[$day];
-+ }
-+ $this->setRecurOnDay($mask);
-+ } else {
-+ // Recur on the day of the week of the original recurrence.
-+ $maskdays = array(HORDE_DATE_SUNDAY => HORDE_DATE_MASK_SUNDAY,
-+ HORDE_DATE_MONDAY => HORDE_DATE_MASK_MONDAY,
-+ HORDE_DATE_TUESDAY => HORDE_DATE_MASK_TUESDAY,
-+ HORDE_DATE_WEDNESDAY => HORDE_DATE_MASK_WEDNESDAY,
-+ HORDE_DATE_THURSDAY => HORDE_DATE_MASK_THURSDAY,
-+ HORDE_DATE_FRIDAY => HORDE_DATE_MASK_FRIDAY,
-+ HORDE_DATE_SATURDAY => HORDE_DATE_MASK_SATURDAY);
-+ $this->setRecurOnDay($maskdays[$this->start->dayOfWeek()]);
-+ }
-+ break;
-+
-+ case 'MP':
-+ $this->setRecurType(NAG_RECUR_MONTHLY_WEEKDAY);
-+ break;
-+
-+ case 'MD':
-+ $this->setRecurType(NAG_RECUR_MONTHLY_DATE);
-+ break;
-+
-+ case 'YM':
-+ $this->setRecurType(NAG_RECUR_YEARLY_DATE);
-+ break;
-+
-+ case 'YD':
-+ $this->setRecurType(NAG_RECUR_YEARLY_DAY);
-+ break;
-+ }
-+
-+ // We don't support modifiers at the moment, strip them.
-+ while ($remainder && !preg_match('/^(#\d+|\d{8})($| |T\d{6})/', $remainder)) {
-+ $remainder = substr($remainder, 1);
-+ }
-+ if (!empty($remainder)) {
-+ if (strpos($remainder, '#') !== false) {
-+ $this->setRecurCount(substr($remainder, 1));
-+ } else {
-+ list($year, $month, $mday) = sscanf($remainder, '%04d%02d%02d');
-+ $this->setRecurEnd(new Horde_Date(array('year' => $year,
-+ 'month' => $month,
-+ 'mday' => $mday)));
-+ }
-+ }
-+ }
-+
-+ /**
-+ * Creates a vCalendar 1.0 recurrence rule.
-+ *
-+ * @link http://www.imc.org/pdi/vcal-10.txt
-+ * @link http://www.shuchow.com/vCalAddendum.html
-+ *
-+ * @param Horde_iCalendar $calendar A Horde_iCalendar object instance.
-+ *
-+ * @return string A vCalendar 1.0 conform RRULE value.
-+ */
-+ function toRRule10($calendar)
-+ {
-+ switch ($this->recurType) {
-+ case NAG_RECUR_NONE:
-+ return '';
-+
-+ case NAG_RECUR_DAILY:
-+ $rrule = 'D' . $this->recurInterval;
-+ break;
-+
-+ case NAG_RECUR_WEEKLY:
-+ $rrule = 'W' . $this->recurInterval;
-+ $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
-+
-+ for ($i = 0; $i <= 7 ; ++$i) {
-+ if ($this->recurOnDay(pow(2, $i))) {
-+ $rrule .= ' ' . $vcaldays[$i];
-+ }
-+ }
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_DATE:
-+ $rrule = 'MD' . $this->recurInterval . ' ' . trim($this->start->mday);
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_WEEKDAY:
-+ $next_week = new Horde_Date($this->start);
-+ $next_week->mday += 7;
-+ $next_week->correct();
-+
-+ if ($this->start->month != $next_week->month) {
-+ $p = 5;
-+ } else {
-+ $p = (int)($this->start->mday / 7);
-+ if (($this->start->mday % 7) > 0) {
-+ $p++;
-+ }
-+ }
-+
-+ $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
-+ $rrule = 'MP' . $this->recurInterval . ' ' . $p . '+ ' . $vcaldays[$this->start->dayOfWeek()];
-+ break;
-+
-+ case NAG_RECUR_YEARLY_DATE:
-+ $rrule = 'YM' . $this->recurInterval . ' ' . trim($this->start->month);
-+ break;
-+
-+ case NAG_RECUR_YEARLY_DAY:
-+ $rrule = 'YD' . $this->recurInterval . ' ' . $this->start->dayOfYear();
-+ break;
-+
-+ default:
-+ return '';
-+ }
-+
-+ return $this->hasRecurEnd() ?
-+ $rrule . ' ' . $calendar->_exportDate($this->recurEnd) :
-+ $rrule . ' #' . (int)$this->getRecurCount();
-+ }
-+
-+ /**
-+ * Parses an iCalendar 2.0 recurrence rule.
-+ *
-+ * @link http://rfc.net/rfc2445.html#s4.8.5
-+ * @link http://www.shuchow.com/vCalAddendum.html
-+ *
-+ * @param string $rrule An iCalendar 2.0 conform RRULE value.
-+ */
-+ function fromRRule20($rrule)
-+ {
-+ // Parse the recurrence rule into keys and values.
-+ $rdata = array();
-+ $parts = explode(';', $rrule);
-+ foreach ($parts as $part) {
-+ list($key, $value) = explode('=', $part, 2);
-+ $rdata[String::upper($key)] = $value;
-+ }
-+
-+ if (isset($rdata['FREQ'])) {
-+ // Always default the recurInterval to 1.
-+ $this->setRecurInterval(isset($rdata['INTERVAL']) ? $rdata['INTERVAL'] : 1);
-+
-+ switch (String::upper($rdata['FREQ'])) {
-+ case 'DAILY':
-+ $this->setRecurType(NAG_RECUR_DAILY);
-+ break;
-+
-+ case 'WEEKLY':
-+ $this->setRecurType(NAG_RECUR_WEEKLY);
-+ if (isset($rdata['BYDAY'])) {
-+ $maskdays = array('SU' => HORDE_DATE_MASK_SUNDAY,
-+ 'MO' => HORDE_DATE_MASK_MONDAY,
-+ 'TU' => HORDE_DATE_MASK_TUESDAY,
-+ 'WE' => HORDE_DATE_MASK_WEDNESDAY,
-+ 'TH' => HORDE_DATE_MASK_THURSDAY,
-+ 'FR' => HORDE_DATE_MASK_FRIDAY,
-+ 'SA' => HORDE_DATE_MASK_SATURDAY);
-+ $days = explode(',', $rdata['BYDAY']);
-+ $mask = 0;
-+ foreach ($days as $day) {
-+ $mask |= $maskdays[$day];
-+ }
-+ $this->setRecurOnDay($mask);
-+ } else {
-+ // Recur on the day of the week of the original
-+ // recurrence.
-+ $maskdays = array(
-+ HORDE_DATE_SUNDAY => HORDE_DATE_MASK_SUNDAY,
-+ HORDE_DATE_MONDAY => HORDE_DATE_MASK_MONDAY,
-+ HORDE_DATE_TUESDAY => HORDE_DATE_MASK_TUESDAY,
-+ HORDE_DATE_WEDNESDAY => HORDE_DATE_MASK_WEDNESDAY,
-+ HORDE_DATE_THURSDAY => HORDE_DATE_MASK_THURSDAY,
-+ HORDE_DATE_FRIDAY => HORDE_DATE_MASK_FRIDAY,
-+ HORDE_DATE_SATURDAY => HORDE_DATE_MASK_SATURDAY);
-+ $this->setRecurOnDay($maskdays[$this->start->dayOfWeek()]);
-+ }
-+ break;
-+
-+ case 'MONTHLY':
-+ if (isset($rdata['BYDAY'])) {
-+ $this->setRecurType(NAG_RECUR_MONTHLY_WEEKDAY);
-+ } else {
-+ $this->setRecurType(NAG_RECUR_MONTHLY_DATE);
-+ }
-+ break;
-+
-+ case 'YEARLY':
-+ if (isset($rdata['BYYEARDAY'])) {
-+ $this->setRecurType(NAG_RECUR_YEARLY_DAY);
-+ } elseif (isset($rdata['BYDAY'])) {
-+ $this->setRecurType(NAG_RECUR_YEARLY_WEEKDAY);
-+ } else {
-+ $this->setRecurType(NAG_RECUR_YEARLY_DATE);
-+ }
-+ break;
-+ }
-+
-+ if (isset($rdata['UNTIL'])) {
-+ list($year, $month, $mday) = sscanf($rdata['UNTIL'],
-+ '%04d%02d%02d');
-+ $this->setRecurEnd(new Horde_Date(array('year' => $year,
-+ 'month' => $month,
-+ 'mday' => $mday)));
-+ }
-+ if (isset($rdata['COUNT'])) {
-+ $this->setRecurCount($rdata['COUNT']);
-+ }
-+ } else {
-+ // No recurrence data - event does not recur.
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ }
-+ }
-+
-+ /**
-+ * Creates an iCalendar 2.0 recurrence rule.
-+ *
-+ * @link http://rfc.net/rfc2445.html#s4.8.5
-+ * @link http://www.shuchow.com/vCalAddendum.html
-+ *
-+ * @param Horde_iCalendar $calendar A Horde_iCalendar object instance.
-+ *
-+ * @return string An iCalendar 2.0 conform RRULE value.
-+ */
-+ function toRRule20($calendar)
-+ {
-+ switch ($this->recurType) {
-+ case NAG_RECUR_NONE:
-+ return '';
-+
-+ case NAG_RECUR_DAILY:
-+ $rrule = 'FREQ=DAILY;INTERVAL=' . $this->recurInterval;
-+ break;
-+
-+ case NAG_RECUR_WEEKLY:
-+ $rrule = 'FREQ=WEEKLY;INTERVAL=' . $this->recurInterval . ';BYDAY=';
-+ $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
-+
-+ for ($i = $flag = 0; $i <= 7 ; ++$i) {
-+ if ($this->recurOnDay(pow(2, $i))) {
-+ if ($flag) {
-+ $rrule .= ',';
-+ }
-+ $rrule .= $vcaldays[$i];
-+ $flag = true;
-+ }
-+ }
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_DATE:
-+ $rrule = 'FREQ=MONTHLY;INTERVAL=' . $this->recurInterval;
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_WEEKDAY:
-+ $next_week = new Horde_Date($this->start);
-+ $next_week->mday += 7;
-+ $next_week->correct();
-+ if ($this->start->month != $next_week->month) {
-+ $p = 5;
-+ } else {
-+ $p = (int)($this->start->mday / 7);
-+ if (($this->start->mday % 7) > 0) {
-+ $p++;
-+ }
-+ }
-+ $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
-+ $rrule = 'FREQ=MONTHLY;INTERVAL=' . $this->recurInterval
-+ . ';BYDAY=' . $p . $vcaldays[$this->start->dayOfWeek()];
-+ break;
-+
-+ case NAG_RECUR_YEARLY_DATE:
-+ $rrule = 'FREQ=YEARLY;INTERVAL=' . $this->recurInterval;
-+ break;
-+
-+ case NAG_RECUR_YEARLY_DAY:
-+ $rrule = 'FREQ=YEARLY;INTERVAL=' . $this->recurInterval
-+ . ';BYYEARDAY=' . $this->start->dayOfYear();
-+ break;
-+
-+ case NAG_RECUR_YEARLY_WEEKDAY:
-+ $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
-+ $weekday = date('W', mktime(0,
-+ 0,
-+ 0,
-+ $this->start->month,
-+ 1,
-+ $this->start->year));
-+ $rrule = 'FREQ=YEARLY;INTERVAL=' . $this->recurInterval
-+ . ';BYDAY=' . ($this->start->weekOfYear() - $weekday + 1)
-+ . $vcaldays[$this->start->dayOfWeek()]
-+ . ';BYMONTH=' . $this->start->month;
-+ break;
-+ }
-+
-+ if ($this->hasRecurEnd()) {
-+ $rrule .= ';UNTIL=' . $calendar->_exportDate($this->recurEnd);
-+ }
-+ if ($count = $this->getRecurCount()) {
-+ $rrule .= ';COUNT=' . $count;
-+ }
-+ return $rrule;
-+ }
-+
-+ /**
-+ * Parses the recurrence data from a hash.
-+ *
-+ * @param array $hash The hash to convert.
-+ *
-+ * @return boolean True if the hash seemed valid, false otherwise.
-+ */
-+ function fromHash($hash)
-+ {
-+ if (!isset($hash['interval']) || !isset($hash['interval']) ||
-+ !isset($hash['range-type'])) {
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ return false;
-+ }
-+
-+ $this->setRecurInterval((int) $hash['interval']);
-+
-+ $parse_day = false;
-+ $set_daymask = false;
-+ $update_month = false;
-+ $update_daynumber = false;
-+ $update_weekday = false;
-+ $nth_weekday = -1;
-+
-+ switch ($hash['cycle']) {
-+ case 'daily':
-+ $this->setRecurType(NAG_RECUR_DAILY);
-+ break;
-+
-+ case 'weekly':
-+ $this->setRecurType(NAG_RECUR_WEEKLY);
-+ $parse_day = true;
-+ $set_daymask = true;
-+ break;
-+
-+ case 'monthly':
-+ if (!isset($hash['daynumber'])) {
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ return false;
-+ }
-+
-+ switch ($hash['type']) {
-+ case 'daynumber':
-+ $this->setRecurType(NAG_RECUR_MONTHLY_DATE);
-+ $update_daynumber = true;
-+ break;
-+
-+ case 'weekday':
-+ $this->setRecurType(NAG_RECUR_MONTHLY_WEEKDAY);
-+ $nth_weekday = (int) $hash['daynumber'];
-+ $hash['daynumber'] = 1;
-+ $parse_day = true;
-+ $update_daynumber = true;
-+ $update_weekday = true;
-+ break;
-+ }
-+ break;
-+
-+ case 'yearly':
-+ if (!isset($hash['type'])) {
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ return false;
-+ }
-+
-+ switch ($hash['type']) {
-+ case 'monthday':
-+ $this->setRecurType(NAG_RECUR_YEARLY_DATE);
-+ $update_month = true;
-+ $update_daynumber = true;
-+ break;
-+
-+ case 'yearday':
-+ if (!isset($hash['month'])) {
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ return false;
-+ }
-+
-+ $this->setRecurType(NAG_RECUR_YEARLY_DAY);
-+ // Start counting days in January.
-+ $hash['month'] = 'january';
-+ $update_month = true;
-+ $update_daynumber = true;
-+ break;
-+
-+ case 'weekday':
-+ if (!isset($hash['daynumber'])) {
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ return false;
-+ }
-+
-+ $this->setRecurType(NAG_RECUR_YEARLY_WEEKDAY);
-+ $nth_weekday = (int) $hash['daynumber'];
-+ $hash['daynumber'] = 1;
-+ $parse_day = true;
-+ $update_month = true;
-+ $update_daynumber = true;
-+ $update_weekday = true;
-+ break;
-+ }
-+ }
-+
-+ switch ($hash['range-type']) {
-+ case 'number':
-+ if (!isset($hash['range'])) {
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ return false;
-+ }
-+
-+ $this->setRecurCount((int) $hash['range']);
-+ break;
-+
-+ case 'date':
-+ $recur_end = new Horde_Date($hash['range']);
-+ $recur_end->hour = 23;
-+ $recur_end->min = 59;
-+ $recur_end->sec = 59;
-+ $this->setRecurEnd($recur_end);
-+ break;
-+ }
-+
-+ // Need to parse <day>?
-+ $last_found_day = -1;
-+ if ($parse_day) {
-+ if (!isset($hash['day'])) {
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ return false;
-+ }
-+
-+ $mask = 0;
-+ $bits = array(
-+ 'monday' => HORDE_DATE_MASK_MONDAY,
-+ 'tuesday' => HORDE_DATE_MASK_TUESDAY,
-+ 'wednesday' => HORDE_DATE_MASK_WEDNESDAY,
-+ 'thursday' => HORDE_DATE_MASK_THURSDAY,
-+ 'friday' => HORDE_DATE_MASK_FRIDAY,
-+ 'saturday' => HORDE_DATE_MASK_SATURDAY,
-+ 'sunday' => HORDE_DATE_MASK_SUNDAY,
-+ );
-+ $days = array(
-+ 'monday' => HORDE_DATE_MONDAY,
-+ 'tuesday' => HORDE_DATE_TUESDAY,
-+ 'wednesday' => HORDE_DATE_WEDNESDAY,
-+ 'thursday' => HORDE_DATE_THURSDAY,
-+ 'friday' => HORDE_DATE_FRIDAY,
-+ 'saturday' => HORDE_DATE_SATURDAY,
-+ 'sunday' => HORDE_DATE_SUNDAY,
-+ );
-+
-+ foreach ($hash['day'] as $day) {
-+ // Validity check.
-+ if (empty($day) || !isset($bits[$day])) {
-+ continue;
-+ }
-+
-+ $mask |= $bits[$day];
-+ $last_found_day = $days[$day];
-+ }
-+
-+ if ($set_daymask) {
-+ $this->setRecurOnDay($mask);
-+ }
-+ }
-+
-+ if ($update_month || $update_daynumber || $update_weekday) {
-+ if ($update_month) {
-+ $month2number = array(
-+ 'january' => 1,
-+ 'february' => 2,
-+ 'march' => 3,
-+ 'april' => 4,
-+ 'may' => 5,
-+ 'june' => 6,
-+ 'july' => 7,
-+ 'august' => 8,
-+ 'september' => 9,
-+ 'october' => 10,
-+ 'november' => 11,
-+ 'december' => 12,
-+ );
-+
-+ if (isset($month2number[$hash['month']])) {
-+ $this->start->month = $month2number[$hash['month']];
-+ }
-+ }
-+
-+ if ($update_daynumber) {
-+ if (!isset($hash['daynumber'])) {
-+ $this->setRecurType(NAG_RECUR_NONE);
-+ return false;
-+ }
-+
-+ $this->start->mday = $hash['daynumber'];
-+ }
-+
-+ if ($update_weekday) {
-+ $this->start->setNthWeekday($last_found_day, $nth_weekday);
-+ }
-+
-+ $this->start->correct();
-+ }
-+
-+ // Exceptions.
-+ if (isset($hash['exceptions'])) {
-+ $this->exceptions = $hash['exceptions'];
-+ }
-+
-+ if (isset($hash['completions'])) {
-+ $this->completions = $hash['completions'];
-+ }
-+
-+ return true;
-+ }
-+
-+ /**
-+ * Export this object into a hash.
-+ *
-+ * @return array The recurrence hash.
-+ */
-+ function toHash()
-+ {
-+ if ($this->getRecurType() == NAG_RECUR_NONE) {
-+ return array();
-+ }
-+
-+ $day2number = array(
-+ 0 => 'sunday',
-+ 1 => 'monday',
-+ 2 => 'tuesday',
-+ 3 => 'wednesday',
-+ 4 => 'thursday',
-+ 5 => 'friday',
-+ 6 => 'saturday'
-+ );
-+ $month2number = array(
-+ 1 => 'january',
-+ 2 => 'february',
-+ 3 => 'march',
-+ 4 => 'april',
-+ 5 => 'may',
-+ 6 => 'june',
-+ 7 => 'july',
-+ 8 => 'august',
-+ 9 => 'september',
-+ 10 => 'october',
-+ 11 => 'november',
-+ 12 => 'december'
-+ );
-+
-+ $hash = array('interval' => $this->getRecurInterval());
-+ $start = $this->getRecurStart();
-+
-+ switch ($this->getRecurType()) {
-+ case NAG_RECUR_DAILY:
-+ $hash['cycle'] = 'daily';
-+ break;
-+
-+ case NAG_RECUR_WEEKLY:
-+ $hash['cycle'] = 'weekly';
-+ $bits = array(
-+ 'monday' => HORDE_DATE_MASK_MONDAY,
-+ 'tuesday' => HORDE_DATE_MASK_TUESDAY,
-+ 'wednesday' => HORDE_DATE_MASK_WEDNESDAY,
-+ 'thursday' => HORDE_DATE_MASK_THURSDAY,
-+ 'friday' => HORDE_DATE_MASK_FRIDAY,
-+ 'saturday' => HORDE_DATE_MASK_SATURDAY,
-+ 'sunday' => HORDE_DATE_MASK_SUNDAY,
-+ );
-+ $days = array();
-+ foreach($bits as $name => $bit) {
-+ if ($this->recurOnDay($bit)) {
-+ $days[] = $name;
-+ }
-+ }
-+ $hash['day'] = $days;
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_DATE:
-+ $hash['cycle'] = 'monthly';
-+ $hash['type'] = 'daynumber';
-+ $hash['daynumber'] = $start->mday;
-+ break;
-+
-+ case NAG_RECUR_MONTHLY_WEEKDAY:
-+ $hash['cycle'] = 'monthly';
-+ $hash['type'] = 'weekday';
-+ $hash['daynumber'] = $start->weekOfMonth();
-+ $hash['day'] = array ($day2number[$start->dayOfWeek()]);
-+ break;
-+
-+ case NAG_RECUR_YEARLY_DATE:
-+ $hash['cycle'] = 'yearly';
-+ $hash['type'] = 'monthday';
-+ $hash['daynumber'] = $start->mday;
-+ $hash['month'] = $month2number[$start->month];
-+ break;
-+
-+ case NAG_RECUR_YEARLY_DAY:
-+ $hash['cycle'] = 'yearly';
-+ $hash['type'] = 'yearday';
-+ $hash['daynumber'] = $start->dayOfYear();
-+ break;
-+
-+ case NAG_RECUR_YEARLY_WEEKDAY:
-+ $hash['cycle'] = 'yearly';
-+ $hash['type'] = 'weekday';
-+ $hash['daynumber'] = $start->weekOfMonth();
-+ $hash['day'] = array ($day2number[$start->dayOfWeek()]);
-+ $hash['month'] = $month2number[$start->month];
-+ }
-+
-+ if ($this->hasRecurCount()) {
-+ $hash['range-type'] = 'number';
-+ $hash['range'] = $this->getRecurCount();
-+ } elseif ($this->hasRecurEnd()) {
-+ $date = $this->getRecurEnd();
-+ $hash['range-type'] = 'date';
-+ $hash['range'] = $date->datestamp();
-+ } else {
-+ $hash['range-type'] = 'none';
-+ $hash['range'] = '';
-+ }
-+
-+ // Recurrence exceptions
-+ $hash['exceptions'] = $this->exceptions;
-+ $hash['completions'] = $this->completions;
-+
-+ return $hash;
-+ }
-+
-+}
-diff -r f7b1e151bdb5 nag/lib/UI/VarRenderer/nag.php
---- a/nag/lib/UI/VarRenderer/nag.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/lib/UI/VarRenderer/nag.php Wed Aug 13 21:37:23 2008 +0200
-@@ -26,6 +26,147 @@
- * @package Nag
- */
- class Horde_UI_VarRenderer_nag extends Horde_UI_VarRenderer_html {
-+
-+ function _renderVarInput_nag_recurrence($form, &$var, &$vars)
-+ {
-+ $var->type->getInfo($vars, $var, $info);
-+
-+ require_once NAG_BASE . '/lib/Recurrence.php';
-+
-+ $r = &new Nag_Recurrence(time());
-+ if (!empty($info)) {
-+ $r->fromHash($info);
-+ }
-+?>
-+<table cellspacing="0">
-+<tr>
-+ <td valign="top" colspan="4">
-+ <table cellspacing="0" width="100%">
-+ <tr>
-+ <td class="nowrap">
-+ <input id="recurnone" type="radio" class="checkbox" name="recur" onclick="clearFields(0);" value="<?php echo NAG_RECUR_NONE ?>"<?php if ($r->hasRecurType(NAG_RECUR_NONE)) echo ' checked="checked"' ?> /><label for="recurnone"> <?php echo _("No recurrence") ?></label>
-+ </td>
-+ </tr>
-+ <tr>
-+ <td class="nowrap">
-+ <input id="recurdaily" type="radio" class="checkbox" name="recur" onclick="setInterval('recur_daily_interval');" value="<?php echo NAG_RECUR_DAILY ?>"<?php if ($r->hasRecurType(NAG_RECUR_DAILY)) echo ' checked="checked"' ?> /><label for="recurdaily"> <?php echo _("Daily: Recurs every") ?>&nbsp;</label>
-+ <input type="text" id="recur_daily_interval" name="recur_daily_interval" size="2" onkeypress="setRecur(1);" onchange="setRecur(1);" value="<?php echo $r->hasRecurType(NAG_RECUR_DAILY) ? $r->getRecurInterval() : '' ?>" />&nbsp;<?php echo Horde::label('recur_daily_interval', _("day(s)")) ?>
-+ </td>
-+ </tr>
-+ <tr>
-+ <td class="nowrap">
-+ <input id="recurweekly" type="radio" class="checkbox" name="recur" onclick="setInterval('recur_weekly_interval');" value="<?php echo NAG_RECUR_WEEKLY ?>"<?php if ($r->hasRecurType(NAG_RECUR_WEEKLY)) echo ' checked="checked"' ?> /><label for="recurweekly"> <?php echo _("Weekly: Recurs every") ?>&nbsp;</label>
-+ <input type="text" id="recur_weekly_interval" name="recur_weekly_interval" size="2" onkeypress="setRecur(2);" onchange="setRecur(2);" value="<?php echo $r->hasRecurType(NAG_RECUR_WEEKLY) ? $r->getRecurInterval() : '' ?>" />&nbsp;
-+ <?php echo Horde::label('recur_weekly_interval', _("week(s) on:")) ?><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-+ <label for="mo"><?php echo _("Mo") ?></label><input id="mo" type="checkbox" class="checkbox" name="weekly[]" onclick="setInterval('recur_weekly_interval');setRecur(2);" value="<?php echo HORDE_DATE_MASK_MONDAY ?>"<?php if ($r->recurOnDay(HORDE_DATE_MASK_MONDAY)) echo ' checked="checked"' ?> />&nbsp;
-+ <label for="tu"><?php echo _("Tu") ?></label><input id="tu" type="checkbox" class="checkbox" name="weekly[]" onclick="setInterval('recur_weekly_interval');setRecur(2);" value="<?php echo HORDE_DATE_MASK_TUESDAY ?>"<?php if ($r->recurOnDay(HORDE_DATE_MASK_TUESDAY)) echo ' checked="checked"' ?> />&nbsp;
-+ <label for="we"><?php echo _("We") ?></label><input id="we" type="checkbox" class="checkbox" name="weekly[]" onclick="setInterval('recur_weekly_interval');setRecur(2);" value="<?php echo HORDE_DATE_MASK_WEDNESDAY ?>"<?php if ($r->recurOnDay(HORDE_DATE_MASK_WEDNESDAY)) echo ' checked="checked"' ?> />&nbsp;
-+ <label for="th"><?php echo _("Th") ?></label><input id="th" type="checkbox" class="checkbox" name="weekly[]" onclick="setInterval('recur_weekly_interval');setRecur(2);" value="<?php echo HORDE_DATE_MASK_THURSDAY ?>"<?php if ($r->recurOnDay(HORDE_DATE_MASK_THURSDAY)) echo ' checked="checked"' ?> />&nbsp;
-+ <label for="fr"><?php echo _("Fr") ?></label><input id="fr" type="checkbox" class="checkbox" name="weekly[]" onclick="setInterval('recur_weekly_interval');setRecur(2);" value="<?php echo HORDE_DATE_MASK_FRIDAY ?>"<?php if ($r->recurOnDay(HORDE_DATE_MASK_FRIDAY)) echo ' checked="checked"' ?> />&nbsp;
-+ <label for="sa"><?php echo _("Sa") ?></label><input id="sa" type="checkbox" class="checkbox" name="weekly[]" onclick="setInterval('recur_weekly_interval');setRecur(2);" value="<?php echo HORDE_DATE_MASK_SATURDAY ?>"<?php if ($r->recurOnDay(HORDE_DATE_MASK_SATURDAY)) echo ' checked="checked"' ?> />&nbsp;
-+ <label for="su"><?php echo _("Su") ?></label><input id="su" type="checkbox" class="checkbox" name="weekly[]" onclick="setInterval('recur_weekly_interval');setRecur(2);" value="<?php echo HORDE_DATE_MASK_SUNDAY ?>"<?php if ($r->recurOnDay(HORDE_DATE_MASK_SUNDAY)) echo ' checked="checked"' ?> />&nbsp;
-+ </td>
-+ </tr>
-+ <tr>
-+ <td class="nowrap">
-+ <input id="recurmonthday" type="radio" class="checkbox" name="recur" onclick="setInterval('recur_day_of_month_interval');" value="<?php echo NAG_RECUR_MONTHLY_DATE ?>"<?php if ($r->hasRecurType(NAG_RECUR_MONTHLY_DATE)) echo ' checked="checked"' ?> /><label for="recurmonthday"> <?php echo _("Monthly: Recurs every") ?>&nbsp;</label>
-+ <input type="text" id="recur_day_of_month_interval" name="recur_day_of_month_interval" size="2" onkeypress="setRecur(3);" onchange="setRecur(3);" value="<?php echo $r->hasRecurType(NAG_RECUR_MONTHLY_DATE) ? $r->getRecurInterval() : '' ?>" />&nbsp;<?php echo Horde::label('recur_day_of_month_interval', _("month(s)") . ' ' . _("on the same date")) ?>
-+ </td>
-+ </tr>
-+ <tr>
-+ <td class="nowrap">
-+ <input id="recurmonthweek" type="radio" class="checkbox" name="recur" onclick="setInterval('recur_week_of_month_interval');" value="<?php echo NAG_RECUR_MONTHLY_WEEKDAY ?>"<?php if ($r->hasRecurType(NAG_RECUR_MONTHLY_WEEKDAY)) echo ' checked="checked"' ?> /><label for="recurmonthweek"> <?php echo _("Monthly: Recurs every") ?>&nbsp;</label>
-+ <input type="text" id="recur_week_of_month_interval" name="recur_week_of_month_interval" size="2" onkeypress="setRecur(4);" onchange="setRecur(4);" value="<?php echo $r->hasRecurType(NAG_RECUR_MONTHLY_WEEKDAY) ? $r->getRecurInterval() : '' ?>" />&nbsp;<?php echo Horde::label('recur_week_of_month_interval', _("month(s)") . ' ' . _("on the same weekday")) ?>
-+ </td>
-+ </tr>
-+ <tr>
-+ <td class="nowrap">
-+ <input id="recuryear" type="radio" class="checkbox" name="recur" onclick="setInterval('recur_yearly_interval');" value="<?php echo NAG_RECUR_YEARLY_DATE ?>"<?php if ($r->hasRecurType(NAG_RECUR_YEARLY_DATE)) echo ' checked="checked"' ?> /><label for="recuryear"> <?php echo _("Yearly: Recurs every") ?>&nbsp;</label>
-+ <input type="text" id="recur_yearly_interval" name="recur_yearly_interval" size="2" onkeypress="setRecur(5);" onchange="setRecur(5);" value="<?php echo $r->hasRecurType(NAG_RECUR_YEARLY_DATE) ? $r->getRecurInterval() : '' ?>" />&nbsp;<?php echo Horde::label('recur_yearly_interval', _("year(s) on the same date")) ?>
-+ </td>
-+ </tr>
-+ <tr>
-+ <td class="nowrap">
-+ <input id="recuryearday" type="radio" class="checkbox" name="recur" onclick="setInterval('recur_yearly_day_interval');" value="<?php echo NAG_RECUR_YEARLY_DAY ?>"<?php if ($r->hasRecurType(NAG_RECUR_YEARLY_DAY)) echo ' checked="checked"' ?> /><label for="recuryearday"> <?php echo _("Yearly: Recurs every") ?>&nbsp;</label>
-+ <input type="text" id="recur_yearly_day_interval" name="recur_yearly_day_interval" size="2" onkeypress="setRecur(6);" onchange="setRecur(6);" value="<?php echo $r->hasRecurType(NAG_RECUR_YEARLY_DAY) ? $r->getRecurInterval() : '' ?>" />&nbsp;<?php echo Horde::label('recur_yearly_day_interval', _("year(s) on the same day of the year")) ?>
-+ </td>
-+ </tr>
-+ <tr>
-+ <td class="nowrap">
-+ <input id="recuryearweekday" type="radio" class="checkbox" name="recur" onclick="setInterval('recur_yearly_weekday_interval');" value="<?php echo NAG_RECUR_YEARLY_WEEKDAY ?>"<?php if ($r->hasRecurType(NAG_RECUR_YEARLY_WEEKDAY)) echo ' checked="checked"' ?> /><label for="recuryearweekday"> <?php echo _("Yearly: Recurs every") ?>&nbsp;</label>
-+ <input type="text" id="recur_yearly_weekday_interval" name="recur_yearly_weekday_interval" size="2" onkeypress="setRecur(7);" onchange="setRecur(7);" value="<?php echo $r->hasRecurType(NAG_RECUR_YEARLY_WEEKDAY) ? $r->getRecurInterval() : '' ?>" />&nbsp;<?php echo Horde::label('recur_yearly_weekday_interval', _("year(s) on the same weekday and month of the year")) ?>
-+ </td>
-+ </tr>
-+ </table>
-+ </td>
-+</tr>
-+</table>
-+<?php
-+ }
-+
-+ function _renderVarInput_nag_recur_end($form, &$var, &$vars)
-+ {
-+ $var->type->getInfo($vars, $var, $recur_end);
-+
-+ require_once NAG_BASE . '/lib/Recurrence.php';
-+
-+ $r = &new Nag_Recurrence(time());
-+ $recurrence = $vars->get('recurrence');
-+ if ($recurrence && $recur_end) {
-+ $recurrence = array_merge($recurrence, $recur_end);
-+ }
-+ $r->fromHash($recurrence);
-+ if ($r->hasRecurEnd()) {
-+ $end = $r->recurEnd;
-+ } else {
-+ if ($vars->exists('task_due')) {
-+ $end = new Horde_Date($vars->get('task_due'));
-+ } else {
-+ $end = new Horde_Date(time());
-+ }
-+ }
-+?>
-+<table cellspacing="0">
-+<tr>
-+ <td colspan="3">
-+ <input id="recurnoend" type="radio" class="checkbox" name="recur_enddate_type" value="none"<?php echo (($r->hasRecurEnd() || $r->hasRecurCount()) ? '' : ' checked="checked"') ?> /><label for="recurnoend"> <?php echo _("No end date") ?></label>
-+ </td>
-+<?php if ($GLOBALS['browser']->hasFeature('dom')): ?>
-+ <td>&nbsp;</td>
-+<?php endif; ?>
-+</tr>
-+<tr>
-+ <td colspan="3">
-+ <input type="radio" class="checkbox" id="recur_enddate_type" name="recur_enddate_type" value="date"<?php echo ($r->hasRecurEnd() ? ' checked="checked"' : '') ?> />
-+ <label for="recur_enddate_year" class="hidden"><?php echo _("Recurrence End Year") ?></label>
-+ <input name="recur_enddate[year]" value="<?php echo $end->year ?>" type="text" id="recur_enddate_year" size="4" maxlength="4" onkeypress="document.<?php echo $form->getName() ?>.recur_enddate_type[1].checked = true;" onchange="document.<?php echo $form->getName() ?>.recur_enddate_type[1].checked = true;" /> -
-+ <label for="recur_enddate_month" class="hidden"><?php echo _("Recurrence End Month") ?></label>
-+ <input name="recur_enddate[month]" value="<?php echo $end->month ?>" type="text" id="recur_enddate_month" size="4" maxlength="4" onkeypress="document.<?php echo $form->getName() ?>.recur_enddate_type[1].checked = true;" onchange="document.<?php echo $form->getName() ?>.recur_enddate_type[1].checked = true;" /> -
-+ <label for="recur_enddate_day" class="hidden"><?php echo _("Recurrence End Day") ?></label>
-+ <input name="recur_enddate[day]" value="<?php echo $end->mday ?>" type="text" id="recur_enddate_day" size="4" maxlength="4" onkeypress="document.<?php echo $form->getName() ?>.recur_enddate_type[1].checked = true;" onchange="document.<?php echo $form->getName() ?>.recur_enddate_type[1].checked = true;" />
-+<?php if ($GLOBALS['browser']->hasFeature('dom')): ?>
-+ </td>
-+ <td>
-+<?php
-+ Horde::addScriptFile('open_calendar.js', 'horde');
-+ echo Horde::link('#', _("Select a date"), '', '', 'openCalendar(\'recur_enddateimg\', \'recur_enddate\'); return false;') . Horde::img('calendar.png', _("Set recurrence end date"), 'id="recur_enddateimg"', $GLOBALS['registry']->getImageDir('horde')) . '</a>';
-+endif;
-+?>
-+ </td>
-+</tr>
-+<tr>
-+ <td colspan="3">
-+ <input type="radio" class="checkbox" name="recur_enddate_type" value="count"<?php echo ($r->getRecurCount() ? ' checked="checked"' : '') ?> />
-+ <input type="text" id="recur_count" name="recur_count" size="2" onkeypress="document.<?php echo $form->getName() ?>.recur_enddate_type[2].checked = true;" onchange="document.<?php echo $form->getName() ?>.recur_enddate_type[2].checked = true;" value="<?php if ($r->getRecurCount()) echo $r->getRecurCount() ?>" />
-+ <label for="recur_count"><?php echo _("recurrences") ?></label>
-+ </td>
-+<?php if ($GLOBALS['browser']->hasFeature('dom')): ?>
-+ <td>&nbsp;</td>
-+<?php endif; ?>
-+</tr>
-+</table>
-+<?php
-+ }
-
- function _renderVarInput_nag_start($form, &$var, &$vars)
- {
-diff -r f7b1e151bdb5 nag/lib/api.php
---- a/nag/lib/api.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/lib/api.php Wed Aug 13 21:37:23 2008 +0200
-@@ -96,6 +96,11 @@
-
- $_services['replace'] = array(
- 'args' => array('uid' => 'string', 'content' => 'string', 'contentType' => 'string'),
-+ 'type' => 'boolean',
-+);
-+
-+$_services['complete'] = array(
-+ 'args' => array('uid' => '{urn:horde}stringArray'),
- 'type' => 'boolean',
- );
-
-@@ -1121,6 +1126,34 @@
- }
-
- /**
-+ * Completes a task identified by UID.
-+ *
-+ * @param string|array $uid Identify the task to complete, either a single UID
-+ * or an array.
-+ *
-+ * @return boolean Success or failure.
-+ */
-+function _nag_complete($uid)
-+{
-+ require_once dirname(__FILE__) . '/base.php';
-+
-+ $storage = &Nag_Driver::singleton();
-+ $task = $storage->getByUID($uid);
-+ if (is_a($task, 'PEAR_Error')) {
-+ return $task;
-+ }
-+
-+ if (!Auth::isAdmin() &&
-+ !array_key_exists($task->tasklist,
-+ Nag::listTasklists(false, PERMS_EDIT))) {
-+ return PEAR::raiseError(_("Permission Denied"));
-+ }
-+
-+ $task->toggleComplete();
-+ return $task->save();
-+}
-+
-+/**
- * Replaces the task identified by UID with the content represented in the
- * specified content type.
- *
-diff -r f7b1e151bdb5 nag/list.php
---- a/nag/list.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/list.php Wed Aug 13 21:37:23 2008 +0200
-@@ -75,10 +75,24 @@
- break;
-
- default:
-+ $tasklist = Util::getFormData('tasklist_id');
-+ if ($tasklist) {
-+ $share = $GLOBALS['nag_shares']->getShare($tasklist);
-+ if (!is_a($share, 'PEAR_Error')) {
-+ $notification->push(sprintf(_("Displaying all tasks from tasklist %s."), $share->get('name')));
-+ $completed = 1;
-+ } else {
-+ $tasklist = null;
-+ }
-+ } else {
-+ $completed = null;
-+ }
- /* Get the full, sorted task list. */
- $tasks = Nag::listTasks($prefs->getValue('sortby'),
- $prefs->getValue('sortdir'),
-- $prefs->getValue('altsortby'));
-+ $prefs->getValue('altsortby'),
-+ $tasklist,
-+ $completed);
- if (is_a($tasks, 'PEAR_Error')) {
- $notification->push($tasks, 'horde.error');
- $tasks = new Nag_Task();
-diff -r f7b1e151bdb5 nag/task.php
---- a/nag/task.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/task.php Wed Aug 13 21:37:23 2008 +0200
-@@ -141,6 +141,19 @@
- $cManager->add($info['category']['value']);
- }
-
-+ /* Handle recurrence. */
-+ if ($info['recurrence'] && $info['due']) {
-+ require_once NAG_BASE . '/lib/Recurrence.php';
-+ $recurrence = &new Nag_Recurrence($info['due']);
-+ $r = $info['recurrence'];
-+ if ($info['recur_end']) {
-+ $r = array_merge($r, $info['recur_end']);
-+ }
-+ $recurrence->fromHash($r);
-+ } else {
-+ $recurrence = null;
-+ }
-+
- /* If a task id is set, we're modifying an existing task.
- * Otherwise, we're adding a new task with the provided
- * attributes. */
-@@ -154,7 +167,8 @@
- $info['category']['value'],
- $info['alarm'], $info['parent'],
- (int)$info['private'],
-- Auth::getAuth());
-+ Auth::getAuth(), null, null,
-+ $recurrence);
-
- if (!is_a($result, 'PEAR_Error') &&
- $info['old_tasklist'] != $info['tasklist_id']) {
-@@ -191,7 +205,8 @@
- $info['category']['value'],
- $info['alarm'], null, $info['parent'],
- (int)$info['private'],
-- Auth::getAuth());
-+ Auth::getAuth(), null,
-+ $recurrence);
- }
-
- /* Check our results. */
-@@ -221,12 +236,7 @@
- if (is_a($share, 'PEAR_Error') || !$share->hasPermission(Auth::getAuth(), PERMS_EDIT)) {
- $notification->push(sprintf(_("Access denied completing task %s."), $task->name), 'horde.error');
- } else {
-- $task->completed = !$task->completed;
-- if ($task->completed) {
-- $task->completed_date = time();
-- } else {
-- $task->completed_date = null;
-- }
-+ $task->toggleComplete();
- $result = $task->save();
- if (is_a($result, 'PEAR_Error')) {
- $notification->push(sprintf(_("There was a problem completing %s: %s"),
-@@ -234,6 +244,13 @@
- } else {
- if ($task->completed) {
- $notification->push(sprintf(_("Completed %s."), $task->name), 'horde.success');
-+ } else if ($task->recurs()) {
-+ if (!empty($task->start)) {
-+ $delay = sprintf(_(" (Delayed until %s)"), Nag::formatDate($task->start, false));
-+ } else {
-+ $delay = '';
-+ }
-+ $notification->push(sprintf(_("Next task recurrence due at %s" . $delay . "."), Nag::formatDate($task->due)), 'horde.success');
- } else {
- $notification->push(sprintf(_("%s is now incomplete."), $task->name), 'horde.success');
- }
-diff -r f7b1e151bdb5 nag/templates/list/task_summaries.inc
---- a/nag/templates/list/task_summaries.inc Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/templates/list/task_summaries.inc Wed Aug 13 21:37:23 2008 +0200
-@@ -4,7 +4,7 @@
- if (!is_a($share, 'PEAR_Error') &&
- $share->hasPermission(Auth::getAuth(), PERMS_EDIT)) {
- if (!$task->completed) {
-- if (!$task->childrenCompleted()) {
-+ if (!$task->childrenCompleted() && !$task->recurs()) {
- $label = _("Incomplete sub tasks, complete them first");
- echo Horde::img('unchecked.png', $label, array('title' => $label));
- } else {
-diff -r f7b1e151bdb5 nag/templates/view/task.inc
---- a/nag/templates/view/task.inc Wed Aug 13 17:47:52 2008 +0200
-+++ b/nag/templates/view/task.inc Wed Aug 13 21:37:23 2008 +0200
-@@ -66,6 +66,54 @@
- </tr>
- <?php endif; ?>
-
-+<?php if ($task->recurs()): ?>
-+<!-- recurrence -->
-+<tr>
-+ <td colspan="2" class="control"><strong><?php echo _("Recurrence") ?></strong></td>
-+</tr>
-+<tr>
-+ <td class="rightAlign" valign="top"><strong><?php echo _("Pattern") ?>&nbsp;&nbsp;</strong></td>
-+ <td valign="top">
-+<?php if ($task->recurrence->hasRecurType(NAG_RECUR_DAILY)): ?>
-+ <?php echo _("Daily: Recurs every") . ' ' . $task->recurrence->getRecurInterval() . ' ' . _("day(s)") ?>
-+<?php elseif ($task->recurrence->hasRecurType(NAG_RECUR_WEEKLY)):
-+ $weekdays = array();
-+ if ($task->recurrence->recurOnDay(HORDE_DATE_MASK_MONDAY)) $weekdays[] = _("Monday");
-+ if ($task->recurrence->recurOnDay(HORDE_DATE_MASK_TUESDAY)) $weekdays[] = _("Tuesday");
-+ if ($task->recurrence->recurOnDay(HORDE_DATE_MASK_WEDNESDAY)) $weekdays[] = _("Wednesday");
-+ if ($task->recurrence->recurOnDay(HORDE_DATE_MASK_THURSDAY)) $weekdays[] = _("Thursday");
-+ if ($task->recurrence->recurOnDay(HORDE_DATE_MASK_FRIDAY)) $weekdays[] = _("Friday");
-+ if ($task->recurrence->recurOnDay(HORDE_DATE_MASK_SATURDAY)) $weekdays[] = _("Saturday");
-+ if ($task->recurrence->recurOnDay(HORDE_DATE_MASK_SUNDAY)) $weekdays[] = _("Sunday");
-+ echo _("Weekly: Recurs every") . ' ' . $task->recurrence->getRecurInterval() . ' ' . _("week(s) on:") . ' ' . implode(', ', $weekdays) ?>
-+<?php elseif ($task->recurrence->hasRecurType(NAG_RECUR_MONTHLY_DATE)): ?>
-+ <?php echo _("Monthly: Recurs every") . ' ' . $task->recurrence->getRecurInterval() . ' ' . _("month(s)") . ' ' . _("on the same date") ?>
-+<?php elseif ($task->recurrence->hasRecurType(NAG_RECUR_MONTHLY_WEEKDAY)): ?>
-+ <?php echo _("Monthly: Recurs every") . ' ' . $task->recurrence->getRecurInterval() . ' ' . _("month(s)") . ' ' . _("on the same weekday") ?>
-+<?php elseif ($task->recurrence->hasRecurType(NAG_RECUR_YEARLY_DATE)): ?>
-+ <?php echo _("Yearly: Recurs every") . ' ' . $task->recurrence->getRecurInterval() . ' ' . _("year(s) on the same date") ?>
-+<?php elseif ($task->recurrence->hasRecurType(NAG_RECUR_YEARLY_DAY)): ?>
-+ <?php echo _("Yearly: Recurs every") . ' ' . $task->recurrence->getRecurInterval() . ' ' . _("year(s) on the same day of the year") ?>
-+<?php elseif ($task->recurrence->hasRecurType(NAG_RECUR_YEARLY_WEEKDAY)): ?>
-+ <?php echo _("Yearly: Recurs every") . ' ' . $task->recurrence->getRecurInterval() . ' ' . _("year(s) on the same weekday and month of the year") ?>
-+<?php endif; ?>
-+ </td>
-+</tr>
-+
-+<!-- recur end date -->
-+<tr>
-+ <td class="rightAlign"><strong><?php echo _("Recur Until") ?>&nbsp;&nbsp;</strong></td>
-+ <td><?php echo $task->recurrence->hasRecurEnd() ? strftime($prefs->getValue('date_format'), $task->recurrence->recurEnd->timestamp()) . date($prefs->getValue('twentyFour') ? ' G:i' : ' g:i a', $task->recurrence->recurEnd->timestamp()) : ($task->recurrence->getRecurCount() ? sprintf(_("%d times"), $task->recurrence->getRecurCount()) : _("No end date")) ?></td>
-+</tr>
-+
-+<?php if ($task->recurrence->getExceptions()): ?>
-+<!-- exceptions -->
-+<tr>
-+ <td class="rightAlign"><strong><?php echo _("Exceptions") ?>&nbsp;&nbsp;</strong></td>
-+ <td><?php echo $task->exceptionsList(); ?></td>
-+</tr>
-+<?php endif; endif; ?>
-+
- <?php if (strlen($task->desc)): ?>
- <tr>
- <td colspan="2" class="taskBody">
-diff -r f7b1e151bdb5 storage/.htaccess
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/storage/.htaccess Wed Aug 13 21:37:23 2008 +0200
-@@ -0,0 +1,1 @@
-+Deny from All
-\ No newline at end of file
-diff -r f7b1e151bdb5 tmp/.htaccess
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/tmp/.htaccess Wed Aug 13 21:37:23 2008 +0200
-@@ -0,0 +1,1 @@
-+Deny from All
-\ No newline at end of file
-diff -r f7b1e151bdb5 turba/config/conf.php
---- a/turba/config/conf.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/turba/config/conf.php Wed Aug 13 21:37:23 2008 +0200
-@@ -3,8 +3,8 @@
- // $Horde: turba/config/conf.xml,v 1.6.2.5 2008/05/06 21:26:59 bklang Exp $
- $conf['menu']['import_export'] = true;
- $conf['menu']['apps'] = array();
--$conf['client']['addressbook'] = 'localsql';
--$conf['shares']['source'] = 'localsql';
-+$conf['client']['addressbook'] = 'INBOX%2FClients';
-+$conf['shares']['source'] = 'kolab';
- $conf['comments']['allow'] = true;
--$conf['documents']['type'] = 'none';
-+$conf['documents']['type'] = 'horde';
- /* CONFIG END. DO NOT CHANGE ANYTHING IN OR BEFORE THIS LINE. */
-diff -r f7b1e151bdb5 turba/config/sources.php
---- a/turba/config/sources.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/turba/config/sources.php Wed Aug 13 21:37:23 2008 +0200
-@@ -149,6 +149,8 @@
- * Here are some example configurations:
- */
-
-+if (empty($GLOBALS['conf']['kolab']['enabled'])) {
-+
- /**
- * A local address book in an SQL database. This implements a private
- * per-user address book. Sharing of this source with other users may be
-@@ -260,3 +262,233 @@
- 'use_shares' => true,
- 'list_name_field' => 'lastname',
- );
-+
-+}
-+
-+/* Begin Kolab sources. */
-+if (!empty($GLOBALS['conf']['kolab']['enabled'])) {
-+
-+ /* Only use LDAP if we have that extension in PHP */
-+ if (function_exists('ldap_connect')) {
-+ require_once 'Horde/Kolab.php';
-+
-+ if (!is_callable('Kolab', 'getServer')) {
-+ $_kolab_server = $GLOBALS['conf']['kolab']['ldap']['server'];
-+ } else {
-+ $_kolab_server = Kolab::getServer('ldap');
-+ }
-+
-+ /* A global address book for a Kolab Server. This is typically a
-+ * read-only public directory, stored in the default Kolab LDAP server.
-+ * The user accessing this should have read permissions to the shared
-+ * directory in LDAP. */
-+ $cfgSources['kolab_global'] = array(
-+ 'title' => _("Global Address Book"),
-+ 'type' => 'ldap',
-+ 'params' => array(
-+ 'server' => $_kolab_server,
-+ 'port' => $GLOBALS['conf']['kolab']['ldap']['port'],
-+ 'tls' => false,
-+ 'root' => $GLOBALS['conf']['kolab']['ldap']['basedn'],
-+ 'sizelimit' => 200,
-+ 'dn' => array('cn'),
-+ 'objectclass' => array(
-+ 'inetOrgPerson'
-+ ),
-+ 'scope' => 'sub',
-+ 'charset' => 'utf-8',
-+ 'version' => 3,
-+ 'bind_dn' => '',
-+ 'bind_password' => '',
-+ ),
-+ 'map' => array(
-+ '__key' => 'dn',
-+ 'name' => 'cn',
-+ 'firstname' => 'givenName',
-+ 'lastname' => 'sn',
-+ 'email' => 'mail',
-+ 'alias' => 'alias',
-+ 'title' => 'title',
-+ 'company' => 'o',
-+ 'workStreet' => 'street',
-+ 'workCity' => 'l',
-+ 'workProvince' => 'st',
-+ 'workPostalCode' => 'postalCode',
-+ 'workCountry' => 'c',
-+ 'homePhone' => 'homePhone',
-+ 'workPhone' => 'telephoneNumber',
-+ 'cellPhone' => 'mobile',
-+ 'fax' => 'fax',
-+ 'notes' => 'description',
-+ 'freebusyUrl' => 'kolabHomeServer',
-+ ),
-+ 'search' => array(
-+ 'name',
-+ 'firstname',
-+ 'lastname',
-+ 'email',
-+ 'title',
-+ 'company',
-+ 'workAddress',
-+ 'workCity',
-+ 'workProvince',
-+ 'workPostalCode',
-+ 'workCountry',
-+ 'homePhone',
-+ 'workPhone',
-+ 'cellPhone',
-+ 'fax',
-+ 'notes',
-+ ),
-+ 'strict' => array(
-+ 'dn',
-+ ),
-+ 'export' => true,
-+ 'browse' => true,
-+ );
-+ }
-+
-+ /**
-+ * The local address books for a Kolab user. These are stored in specially
-+ * flagged contact folder within the users Cyrus IMAP mailbox.
-+ *
-+ * Still missing attributes are:
-+ *
-+ * picture, sensitivity
-+ */
-+
-+ $cfgSources['kolab'] = array(
-+ 'title' => _("Contacts"),
-+ 'type' => 'kolab',
-+ 'params' => array(
-+ 'charset' => 'utf-8',
-+ ),
-+ 'list_name_field' => 'lastname',
-+ 'map' => array(
-+ '__key' => 'uid',
-+ '__uid' => 'uid',
-+ '__type' => '__type',
-+ '__members' => '__members',
-+ /* Personal */
-+ 'name' => array('fields' => array('firstname', 'middlenames', 'lastname'),
-+ 'format' => '%s %s %s',
-+ 'attribute' => 'full-name'),
-+ 'firstname' => 'given-name',
-+ 'lastname' => 'last-name',
-+ 'middlenames' => 'middle-names',
-+ 'namePrefix' => 'prefix',
-+ 'nameSuffix' => 'suffix',
-+ 'initials' => 'initials',
-+ 'nickname' => 'nick-name',
-+ 'gender' => 'gender',
-+ 'birthday' => 'birthday',
-+ 'spouse' => 'spouse-name',
-+ 'anniversary' => 'anniversary',
-+ 'children' => 'children',
-+ /* Location */
-+ 'workStreet' => 'addr-business-street',
-+ 'workCity' => 'addr-business-locality',
-+ 'workProvince' => 'addr-business-region',
-+ 'workPostalCode' => 'addr-business-postal-code',
-+ 'workCountry' => 'addr-business-country',
-+ 'homeStreet' => 'addr-home-street',
-+ 'homeCity' => 'addr-home-locality',
-+ 'homeProvince' => 'addr-home-region',
-+ 'homePostalCode' => 'addr-home-postal-code',
-+ 'homeCountry' => 'addr-home-country',
-+ /* Communications */
-+ 'emails' => 'emails',
-+ 'homePhone' => 'phone-home1',
-+ 'workPhone' => 'phone-business1',
-+ 'cellPhone' => 'phone-mobile',
-+ 'fax' => 'phone-businessfax',
-+ 'instantMessenger' => 'im-address',
-+ /* Organization */
-+ 'title' => 'job-title',
-+ 'role' => 'profession',
-+ 'company' => 'organization',
-+ 'department' => 'department',
-+ 'office' => 'office-location',
-+ 'manager' => 'manager-name',
-+ 'assistant' => 'assistant',
-+ /* Other */
-+ 'category' => 'categories',
-+ 'notes' => 'body',
-+ 'website' => 'web-page',
-+ 'freebusyUrl' => 'free-busy-url',
-+ 'language' => 'language',
-+ 'latitude' => 'latitude',
-+ 'longitude' => 'longitude',
-+ ),
-+ 'tabs' => array(
-+ _("Personal") => array('name', 'firstname', 'lastname', 'middlenames',
-+ 'namePrefix', 'nameSuffix', 'initials', 'nickname',
-+ 'gender', 'birthday', 'spouse', 'anniversary',
-+ 'children'),
-+ _("Location") => array('homeStreet', 'homeCity', 'homeProvince',
-+ 'homePostalCode', 'homeCountry', 'workStreet',
-+ 'workCity', 'workProvince', 'workPostalCode',
-+ 'workCountry'),
-+ _("Communications") => array('emails', 'homePhone', 'workPhone',
-+ 'cellPhone', 'fax', 'instantMessenger'),
-+ _("Organization") => array('title', 'role', 'company', 'department',
-+ 'office', 'manager', 'assistant'),
-+ _("Other") => array('category', 'notes', 'website', 'freebusyUrl',
-+ 'language', 'latitude', 'longitude'),
-+ ),
-+ 'search' => array(
-+ /* Personal */
-+ 'firstname',
-+ 'lastname',
-+ 'middlenames',
-+ 'namePrefix',
-+ 'nameSuffix',
-+ 'initials',
-+ 'nickname',
-+ 'gender',
-+ 'birthday',
-+ 'spouse',
-+ 'anniversary',
-+ 'children',
-+ /* Location */
-+ 'workStreet',
-+ 'workCity',
-+ 'workProvince',
-+ 'workPostalCode',
-+ 'workCountry',
-+ 'homeStreet',
-+ 'homeCity',
-+ 'homeProvince',
-+ 'homePostalCode',
-+ 'homeCountry',
-+ /* Communications */
-+ 'emails',
-+ 'homePhone',
-+ 'workPhone',
-+ 'cellPhone',
-+ 'fax',
-+ 'instantMessenger',
-+ /* Organization */
-+ 'title',
-+ 'role',
-+ 'company',
-+ 'department',
-+ 'office',
-+ 'manager',
-+ 'assistant',
-+ /* Other */
-+ 'category',
-+ 'notes',
-+ 'website',
-+ 'language',
-+ ),
-+ 'strict' => array(
-+ 'uid',
-+ ),
-+ 'export' => true,
-+ 'browse' => true,
-+ 'use_shares' => true,
-+ 'shares_only' => true,
-+ );
-+}
-+/* End Kolab sources. */
-diff -r f7b1e151bdb5 turba/lib/Driver.php
---- a/turba/lib/Driver.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/turba/lib/Driver.php Wed Aug 13 21:37:23 2008 +0200
-@@ -1368,9 +1368,6 @@
- $hash = array();
- $attr = $vcard->getAllAttributes();
- foreach ($attr as $item) {
-- if (empty($item['value'])) {
-- continue;
-- }
-
- switch ($item['name']) {
- case 'FN':
-diff -r f7b1e151bdb5 turba/lib/Driver/share.php
---- a/turba/lib/Driver/share.php Wed Aug 13 17:47:52 2008 +0200
-+++ b/turba/lib/Driver/share.php Wed Aug 13 21:37:23 2008 +0200
-@@ -145,7 +145,7 @@
- function _deleteAll($sourceName = null)
- {
- if (is_null($sourceName)) {
-- $sourceName = $this->getContactOwner();
-+ $sourceName = $this->getName();
- }
- return $this->_driver->_deleteAll($sourceName);
- }