From 5b24abd33f87c265d5b2a3cd37084a9b5273e806 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 26 Aug 2011 21:35:21 +0200 Subject: [PATCH 1/4] Show saving... message when submitting calendar edit dialog --- plugins/calendar/calendar.php | 2 ++ plugins/calendar/calendar_ui.js | 1 + 2 files changed, 3 insertions(+) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 6d4f30bc..2704b4a9 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -508,6 +508,8 @@ class calendar extends rcube_plugin $this->rc->output->show_message($error_msg, 'error'); } + $this->rc->output->command('plugin.unlock_saving'); + // TODO: keep view and date selection if ($success && $reload) $this->rc->output->redirect(''); diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index 1933b07b..af8fbb40 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -1625,6 +1625,7 @@ function rcube_calendar_ui(settings) if (calendar.id) data.id = calendar.id; + me.saving_lock = rcmail.set_busy(true, 'calendar.savingdata'); rcmail.http_post('calendar', { action:(calendar.id ? 'edit' : 'new'), c:data }); $dialog.dialog("close"); }; From a9a1639abe6a0e2281e83ccd77499e01a6a516bb Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 26 Aug 2011 23:22:36 +0200 Subject: [PATCH 2/4] Add new method to check subscription state of a Kolab folder --- plugins/kolab_core/rcube_kolab.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/plugins/kolab_core/rcube_kolab.php b/plugins/kolab_core/rcube_kolab.php index d5b87c51..ef74d361 100644 --- a/plugins/kolab_core/rcube_kolab.php +++ b/plugins/kolab_core/rcube_kolab.php @@ -187,6 +187,32 @@ class rcube_kolab return self::$ready ? $kolab->getFolder($folder) : null; } + /** + * Checks if the given folder is subscribed. + * Much nicer would be if the Kolab_Folder object could tell this information + * + * @param string Full IMAP folder name + * @return boolean True if in the list of subscribed folders, False if not + */ + public static function is_subscribed($folder) + { + static $subscribed; // local cache + + if (!$subscribed) { + $rcmail = rcmail::get_instance(); + // try without connection first (list could be served from cache) + $subscribed = $rcmail->imap->list_mailboxes(); + + // now really get the list from the IMAP server + if (empty($subscribed) || $subscribed == array('INBOX')) { + $rcmail->imap_connect(); + $subscribed = $rcmail->imap->list_mailboxes(); + } + } + + return in_array($folder, $subscribed); + } + /** * Get storage object for read/write access to the Kolab backend * From dfc304bc02afac294e593a9755ec20e0bd6c0d3e Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 26 Aug 2011 23:24:49 +0200 Subject: [PATCH 3/4] Delegate calendar subscription to driver; use IMAP folder subscriptions for Kolab backend (#245) --- plugins/calendar/calendar.php | 7 ++- plugins/calendar/calendar_ui.js | 7 +-- plugins/calendar/drivers/calendar_driver.php | 10 +++ .../drivers/database/database_driver.php | 23 ++++++- .../calendar/drivers/kolab/kolab_calendar.php | 5 ++ .../calendar/drivers/kolab/kolab_driver.php | 61 ++++++++++++++++--- plugins/calendar/lib/calendar_ui.php | 3 +- 7 files changed, 96 insertions(+), 20 deletions(-) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 2704b4a9..bcb9eb21 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -499,6 +499,10 @@ class calendar extends rcube_plugin if ($success = $this->driver->remove_calendar($cal)) $this->rc->output->command('plugin.destroy_source', array('id' => $cal['id'])); break; + case "subscribe": + if (!$this->driver->subscribe_calendar($cal)) + $this->rc->output->show_message($this->gettext('errorsaving'), 'error'); + return; } if ($success) @@ -797,9 +801,6 @@ class calendar extends rcube_plugin ); $settings['today'] = rcube_label('today'); - // user prefs - $settings['hidden_calendars'] = array_filter(explode(',', $this->rc->config->get('hidden_calendars', ''))); - // get user identity to create default attendee if ($this->ui->screen == 'calendar') { foreach ($this->rc->user->list_identities() as $rec) { diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index af8fbb40..49eefccd 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -1815,8 +1815,7 @@ function rcube_calendar_ui(settings) id: id }, cal); - if ((active = ($.inArray(String(id), settings.hidden_calendars) < 0))) { - this.calendars[id].active = true; + if ((active = cal.active || false)) { event_sources.push(this.calendars[id]); } @@ -1829,17 +1828,15 @@ function rcube_calendar_ui(settings) if (this.checked) { action = 'addEventSource'; me.calendars[id].active = true; - settings.hidden_calendars = $.map(settings.hidden_calendars, function(v){ return v == id ? null : v; }); } else { action = 'removeEventSource'; me.calendars[id].active = false; - settings.hidden_calendars.push(id); } // add/remove event source fc.fullCalendar(action, me.calendars[id]); - rcmail.save_pref({ name:'hidden_calendars', value:settings.hidden_calendars.join(',') }); + rcmail.http_post('calendar', { action:'subscribe', c:{ id:id, active:me.calendars[id].active?1:0 } }); } }).data('id', id).get(0).checked = active; diff --git a/plugins/calendar/drivers/calendar_driver.php b/plugins/calendar/drivers/calendar_driver.php index b1cd580c..10aa3bae 100644 --- a/plugins/calendar/drivers/calendar_driver.php +++ b/plugins/calendar/drivers/calendar_driver.php @@ -113,6 +113,16 @@ abstract class calendar_driver * @return boolean True on success, Fales on failure */ abstract function edit_calendar($prop); + + /** + * Set active/subscribed state of a calendar + * + * @param array Hash array with calendar properties + * id: Calendar Identifier + * active: True if calendar is active, false if not + * @return boolean True on success, Fales on failure + */ + abstract function subscribe_calendar($prop); /** * Delete the given calendar with all its contents diff --git a/plugins/calendar/drivers/database/database_driver.php b/plugins/calendar/drivers/database/database_driver.php index 5e8515ca..eafbfdc8 100644 --- a/plugins/calendar/drivers/database/database_driver.php +++ b/plugins/calendar/drivers/database/database_driver.php @@ -76,6 +76,8 @@ class database_driver extends calendar_driver */ private function _read_calendars() { + $hidden = array_filter(explode(',', $this->rc->config->get('hidden_calendars', ''))); + if (!empty($this->rc->user->ID)) { $calendar_ids = array(); $result = $this->rc->db->query( @@ -85,6 +87,7 @@ class database_driver extends calendar_driver ); while ($result && ($arr = $this->rc->db->fetch_assoc($result))) { $arr['showalarms'] = intval($arr['showalarms']); + $arr['active'] = !in_array($arr['id'], $hidden); $this->calendars[$arr['calendar_id']] = $arr; $calendar_ids[] = $this->rc->db->quote($arr['calendar_id']); } @@ -131,7 +134,7 @@ class database_driver extends calendar_driver return false; } - + /** * Update properties of an existing calendar * @@ -154,6 +157,24 @@ class database_driver extends calendar_driver return $this->rc->db->affected_rows($query); } + /** + * Set active/subscribed state of a calendar + * Save a list of hidden calendars in user prefs + * + * @see calendar_driver::subscribe_calendar() + */ + public function subscribe_calendar($prop) + { + $hidden = array_flip(explode(',', $this->rc->config->get('hidden_calendars', ''))); + + if ($prop['active']) + unset($hidden[$prop['id']]); + else + $hidden[$prop['id']] = 1; + + return $this->rc->user->save_prefs(array('hidden_calendars' => join(',', array_keys($hidden)))); + } + /** * Delete the given calendar with all its contents * diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php index b5f852db..b91574c9 100644 --- a/plugins/calendar/drivers/kolab/kolab_calendar.php +++ b/plugins/calendar/drivers/kolab/kolab_calendar.php @@ -152,6 +152,11 @@ class kolab_calendar */ public function get_color() { + // color is defined in folder METADATA + if ($color = $this->storage->_folder->getKolabAttribute('color')) { + return $color; + } + // Store temporarily calendar color in user prefs (will be changed) $prefs = $this->cal->rc->config->get('kolab_calendars', array()); diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index edf1708f..01e34d58 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -133,6 +133,7 @@ class kolab_driver extends calendar_driver 'readonly' => $cal->readonly, 'showalarms' => $cal->alarms, 'class_name' => $cal->get_namespace(), + 'active' => rcube_kolab::is_subscribed($cal->get_realname()), ); } } @@ -156,15 +157,24 @@ class kolab_driver extends calendar_driver if ($folder === false) { return false; } + + // subscribe to new calendar by default + $this->rc->imap_connect(); + $this->rc->imap->subscribe($folder); // create ID $id = rcube_kolab::folder_id($folder); // save color in user prefs (temp. solution) $prefs['kolab_calendars'] = $this->rc->config->get('kolab_calendars', array()); - $prefs['kolab_calendars'][$id]['color'] = $prop['color']; - $this->rc->user->save_prefs($prefs); + if (isset($prop['color'])) + $prefs['kolab_calendars'][$id]['color'] = $prop['color']; + if (isset($prop['showalarms'])) + $prefs['kolab_calendars'][$id]['showalarms'] = $prop['showalarms'] ? true : false; + + if ($prefs['kolab_calendars'][$id]) + $this->rc->user->save_prefs($prefs); return $id; } @@ -188,17 +198,41 @@ class kolab_driver extends calendar_driver // create ID $id = rcube_kolab::folder_id($newfolder); - // save color and alarms in user prefs (temp. solution) + // fallback to local prefs $prefs['kolab_calendars'] = $this->rc->config->get('kolab_calendars', array()); unset($prefs['kolab_calendars'][$prop['id']]); - $prefs['kolab_calendars'][$id]['color'] = $prop['color']; - $prefs['kolab_calendars'][$id]['showalarms'] = $prop['showalarms'] ? true : false; - $this->rc->user->save_prefs($prefs); + if (isset($prop['color'])) + $prefs['kolab_calendars'][$id]['color'] = $prop['color']; + if (isset($prop['showalarms'])) + $prefs['kolab_calendars'][$id]['showalarms'] = $prop['showalarms'] ? true : false; + + if ($prefs['kolab_calendars'][$id]) + $this->rc->user->save_prefs($prefs); + return true; } - return false; + return false; + } + + + /** + * Set active/subscribed state of a calendar + * + * @see calendar_driver::subscribe_calendar() + */ + public function subscribe_calendar($prop) + { + if ($prop['id'] && ($cal = $this->calendars[$prop['id']])) { + $this->rc->imap_connect(); + if ($prop['active']) + return $this->rc->imap->subscribe($cal->get_realname()); + else + return $this->rc->imap->unsubscribe($cal->get_realname()); + } + + return false; } @@ -209,7 +243,7 @@ class kolab_driver extends calendar_driver * * @return mixed New folder name or False on failure */ - private function folder_update($prop) + private function folder_update(&$prop) { $folder = rcube_charset_convert($prop['name'], RCMAIL_CHARSET, 'UTF7-IMAP'); $oldfolder = $prop['oldname']; // UTF7 @@ -280,7 +314,16 @@ class kolab_driver extends calendar_driver if (!($result = rcube_kolab::folder_create($folder, 'event', false))) $this->last_error = rcube_kolab::$last_error; } - +/* + // save color in METADATA + // TODO: also save 'showalarams' and other properties here + if ($result && $prop['color']) { + if (!($meta_saved = $this->rc->imap->set_metadata($folder, array('/shared/vendor/kolab/color' => $prop['color'])))) // try in shared namespace + $meta_saved = $this->rc->imap->set_metadata($folder, array('/private/vendor/kolab/color' => $prop['color'])); // try in private namespace + if ($meta_saved) + unset($prop['color']); // unsetting will prevent fallback to local user prefs + } +*/ return $result ? $folder : false; } diff --git a/plugins/calendar/lib/calendar_ui.php b/plugins/calendar/lib/calendar_ui.php index c0015f45..804ba4f6 100644 --- a/plugins/calendar/lib/calendar_ui.php +++ b/plugins/calendar/lib/calendar_ui.php @@ -129,7 +129,6 @@ class calendar_ui function calendar_list($attrib = array()) { $calendars = $this->calendar->driver->list_calendars(); - $hidden = explode(',', $this->rc->config->get('hidden_calendars', '')); $li = ''; foreach ((array)$calendars as $id => $prop) { @@ -152,7 +151,7 @@ class calendar_ui $class .= ' '.$prop['class_name']; $li .= html::tag('li', array('id' => 'rcmlical' . $html_id, 'class' => $class), - html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => !in_array($id, $hidden)), '') . html::span(null, Q($prop['name']))); + html::tag('input', array('type' => 'checkbox', 'name' => '_cal[]', 'value' => $id, 'checked' => $prop['active']), '') . html::span(null, Q($prop['name']))); } $this->rc->output->set_env('calendars', $jsenv); From 0814c9884920e05bbcaa0ffdc74e272dd06437cb Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Sat, 27 Aug 2011 00:06:42 +0200 Subject: [PATCH 4/4] Bugfix: fix week selection if properties vars are not set yet --- plugins/calendar/calendar_ui.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index 49eefccd..05f440bd 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -2156,8 +2156,10 @@ function rcube_calendar_ui(settings) var cell = $(e.target); if (e.target.tagName == 'TD' && cell.hasClass('ui-datepicker-week-col')) { var base_date = minical.datepicker('getDate'); - base_date.setMonth(minical.data('month')-1); - base_date.setYear(minical.data('year')); + if (minical.data('month')) + base_date.setMonth(minical.data('month')-1); + if (minical.data('year')) + base_date.setYear(minical.data('year')); var day_off = base_date.getDay() - 1; if (day_off < 0) day_off = 6; var base_kw = $.datepicker.iso8601Week(base_date);