Projects
Kolab:Winterfell
roundcubemail-plugins-kolab
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 64
View file
roundcubemail-plugins-kolab.spec
Changed
@@ -29,7 +29,7 @@ %global tmpdir %{_var}/lib/roundcubemail Name: roundcubemail-plugins-kolab -Version: 3.3.3 +Version: 3.3.4 Release: 1%{?dist} Summary: Kolab Groupware plugins for Roundcube Webmail @@ -2005,6 +2005,9 @@ %defattr(-,root,root,-) %changelog +* Mon Oct 2 2017 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 3.3.4-1 +- Release of version 3.3.4 + * Wed Jul 19 2017 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 3.3.3-1 - Release of version 3.3.3
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +roundcubemail-plugins-kolab (1:3.3.4-0~kolab2) unstable; urgency=low + + * Actual 3.3.4 this time + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Mon, 2 Oct 2017 11:11:11 +0200 + roundcubemail-plugins-kolab (1:3.3.4-0~kolab1) unstable; urgency=low * Release 3.3.3
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/calendar.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/calendar.php
Changed
@@ -857,8 +857,8 @@ if ($success && $reload) $this->rc->output->command('plugin.reload_view'); } - - + + /** * Dispatcher for event actions initiated by the client */ @@ -867,7 +867,7 @@ $action = rcube_utils::get_input_value('action', rcube_utils::INPUT_GPC); $event = rcube_utils::get_input_value('e', rcube_utils::INPUT_POST, true); $success = $reload = $got_msg = false; - + // force notify if hidden + active if ((int)$this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']) === 1) $event['_notify'] = 1; @@ -887,8 +887,10 @@ case "new": // create UID for new event $event['uid'] = $this->generate_uid(); - $this->write_preprocess($event, $action); - if ($success = $this->driver->new_event($event)) { + if (!$this->write_preprocess($event, $action)) { + $got_msg = true; + } + else if ($success = $this->driver->new_event($event)) { $event['id'] = $event['uid']; $event['_savemode'] = 'all'; $this->cleanup_event($event); @@ -898,8 +900,10 @@ break; case "edit": - $this->write_preprocess($event, $action); - if ($success = $this->driver->edit_event($event)) { + if (!$this->write_preprocess($event, $action)) { + $got_msg = true; + } + else if ($success = $this->driver->edit_event($event)) { $this->cleanup_event($event); $this->event_save_success($event, $old, $action, $success); } @@ -907,19 +911,23 @@ break; case "resize": - $this->write_preprocess($event, $action); - if ($success = $this->driver->resize_event($event)) { + if (!$this->write_preprocess($event, $action)) { + $got_msg = true; + } + else if ($success = $this->driver->resize_event($event)) { $this->event_save_success($event, $old, $action, $success); } $reload = $event['_savemode'] ? 2 : 1; break; case "move": - $this->write_preprocess($event, $action); - if ($success = $this->driver->move_event($event)) { + if (!$this->write_preprocess($event, $action)) { + $got_msg = true; + } + else if ($success = $this->driver->move_event($event)) { $this->event_save_success($event, $old, $action, $success); } - $reload = $success && $event['_savemode'] ? 2 : 1; + $reload = $success && $event['_savemode'] ? 2 : 1; break; case "remove": @@ -1184,7 +1192,7 @@ // unlock client $this->rc->output->command('plugin.unlock_saving'); - // update event object on the client or trigger a complete refretch if too complicated + // update event object on the client or trigger a complete refresh if too complicated if ($reload) { $args = array('source' => $event['calendar']); if ($reload > 1) @@ -1732,6 +1740,18 @@ $settings['identity'] = array('name' => $identity['name'], 'email' => strtolower($identity['email']), 'emails' => ';' . strtolower(join(';', $identity['emails']))); } + // freebusy token authentication URL + if (($url = $this->rc->config->get('calendar_freebusy_session_auth_url')) + && ($uniqueid = $this->rc->config->get('kolab_uniqueid')) + ) { + if ($url === true) $url = '/freebusy'; + $url = rtrim(rcube_utils::resolve_url($url), '/ '); + $url .= '/' . urlencode($this->rc->get_user_name()); + $url .= '/' . urlencode($uniqueid); + + $settings['freebusy_url'] = $url; + } + return $settings; } @@ -1981,12 +2001,31 @@ // start/end is all we need for 'move' action (#1480) if ($action == 'move') { - return; + return true; } // convert the submitted recurrence settings if (is_array($event['recurrence'])) { $event['recurrence'] = $this->lib->from_client_recurrence($event['recurrence'], $event['start']); + + // align start date with the first occurrence + if (!empty($event['recurrence']) && !empty($event['syncstart']) + && (empty($event['_savemode']) || $event['_savemode'] == 'all') + ) { + $next = $this->find_first_occurrence($event); + + if (!$next) { + $this->rc->output->show_message('calendar.recurrenceerror', 'error'); + return false; + } + else if ($event['start'] != $next) { + $diff = $event['start']->diff($event['end'], true); + + $event['start'] = $next; + $event['end'] = clone $next; + $event['end']->add($diff); + } + } } // convert the submitted alarm values @@ -2063,6 +2102,8 @@ $event['url'] = $event['vurl']; unset($event['vurl']); } + + return true; } /** @@ -3436,6 +3477,35 @@ } /** + * Find first occurrence of a recurring event excluding start date + * + * @param array $event Event data (with 'start' and 'recurrence') + * + * @return DateTime Date of the first occurrence + */ + public function find_first_occurrence($event) + { + // Make sure libkolab plugin is loaded in case of Kolab driver + $this->load_driver(); + + // Use libkolab to compute recurring events (and libkolab plugin) + // Horde-based fallback has many bugs + if (class_exists('kolabformat') && class_exists('kolabcalendaring') && class_exists('kolab_date_recurrence')) { + $object = kolab_format::factory('event', 3.0); + $object->set($event); + + $recurrence = new kolab_date_recurrence($object); + } + else { + // fallback to libcalendaring (Horde-based) recurrence implementation + require_once(__DIR__ . '/lib/calendar_recurrence.php'); + $recurrence = new calendar_recurrence($this, $event); + } + + return $recurrence->first_occurrence(); + } + + /** * Magic getter for public access to protected members */ public function __get($name)
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/calendar_ui.js -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/calendar_ui.js
Changed
@@ -477,7 +477,7 @@ data = event.attendees[j]; if (data.email) { if (data.role != 'ORGANIZER' && settings.identity.emails.indexOf(';'+data.email) >= 0) { - mystatus = data.status.toLowerCase(); + mystatus = (data.status || 'UNKNOWN').toLowerCase(); if (data.status == 'NEEDS-ACTION' || data.status == 'TENTATIVE' || data.rsvp) rsvp = mystatus; } @@ -519,7 +519,7 @@ if (mystatus && !rsvp) { $('#event-partstat').show().children('.changersvp') - .removeClass('accepted tentative declined delegated needs-action') + .removeClass('accepted tentative declined delegated needs-action unknown') .addClass(mystatus) .children('.event-text') .text(rcmail.gettext('status' + mystatus, 'libcalendaring')); @@ -527,7 +527,7 @@ var show_rsvp = rsvp && !organizer && event.status != 'CANCELLED' && me.has_permission(calendar, 'v'); $('#event-rsvp')[(show_rsvp ? 'show' : 'hide')](); - $('#event-rsvp .rsvp-buttons input').prop('disabled', false).filter('input[rel='+mystatus+']').prop('disabled', true); + $('#event-rsvp .rsvp-buttons input').prop('disabled', false).filter('input[rel="'+(mystatus || '')+'"]').prop('disabled', true); if (show_rsvp && event.comment) $('#event-rsvp-comment').show().children('.event-text').html(Q(event.comment)); @@ -678,7 +678,7 @@ var freebusy = $('#edit-free-busy').val(event.free_busy); var priority = $('#edit-priority').val(event.priority); var sensitivity = $('#edit-sensitivity').val(event.sensitivity); - + var syncstart = $('#edit-recurrence-syncstart input'); var duration = Math.round((event.end.getTime() - event.start.getTime()) / 1000); var startdate = $('#edit-startdate').val($.fullCalendar.formatDate(event.start, settings['date_format'])).data('duration', duration); var starttime = $('#edit-starttime').val($.fullCalendar.formatDate(event.start, settings['time_format'])).show(); @@ -898,6 +898,9 @@ data._fromcalendar = event.calendar; } + if (data.recurrence && syncstart.is(':checked')) + data.syncstart = 1; + update_event(action, data); $dialog.dialog("close"); } // end click: @@ -3200,6 +3203,27 @@ } }; + // show free-busy URL in a dialog box + this.showfburl = function() + { + var $dialog = $('#fburlbox'); + + if ($dialog.is(':ui-dialog')) + $dialog.dialog('close'); + + $dialog.dialog({ + resizable: true, + closeOnEscape: true, + title: rcmail.gettext('showfburl', 'calendar'), + close: function() { + $dialog.dialog("destroy").hide(); + }, + width: 520 + }).show(); + + $('#fburl').val(settings.freebusy_url).select(); + }; + // refresh the calendar view after saving event data this.refresh = function(p) { @@ -3601,7 +3625,7 @@ calendars_list.addEventListener('select', function(node) { if (node && node.id && me.calendars[node.id]) { me.select_calendar(node.id, true); - rcmail.enable_command('calendar-edit', 'calendar-showurl', true); + rcmail.enable_command('calendar-edit', 'calendar-showurl', 'calendar-showfburl', true); rcmail.enable_command('calendar-delete', me.calendars[node.id].editable); rcmail.enable_command('calendar-remove', me.calendars[node.id] && me.calendars[node.id].removable); } @@ -3953,8 +3977,15 @@ $('#edit-attendees-form .attendees-invitebox').show(); } } + // reset autocompletion on tab change (#3389) rcmail.ksearch_blur(); + + // display recurrence warning in recurrence tab only + if (tab == 'recurrence') + $('#edit-recurrence-frequency').change(); + else + $('#edit-recurrence-syncstart').hide(); } }); $('#edit-enddate').datepicker(datepicker_settings); @@ -4162,6 +4193,7 @@ rcmail.register_command('calendar-delete', function(){ cal.calendar_delete(cal.calendars[cal.selected_calendar]); }, false); rcmail.register_command('events-import', function(){ cal.import_events(cal.calendars[cal.selected_calendar]); }, true); rcmail.register_command('calendar-showurl', function(){ cal.showurl(cal.calendars[cal.selected_calendar]); }, false); + rcmail.register_command('calendar-showfburl', function(){ cal.showfburl(); }, false); rcmail.register_command('event-download', function(){ cal.event_download(cal.selected_event); }, true); rcmail.register_command('event-sendbymail', function(p, obj, e){ cal.event_sendbymail(cal.selected_event, e); }, true); rcmail.register_command('event-copy', function(){ cal.event_copy(cal.selected_event); }, true);
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/composer.json -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Calendar plugin", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.3.3", + "version": "3.3.4", "authors": [ { "name": "Thomas Bruederli",
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/config.inc.php.dist -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/config.inc.php.dist
Changed
@@ -166,4 +166,9 @@ // LDAP directory configuration to find avilable resources for events // $config['calendar_resources_directory'] = array(/* ldap_public-like address book configuration */); +// Enables displaying of free-busy URL with token-based authentication +// Set it to the prefix URL, e.g. 'https://hostname/freebusy' or just '/freebusy'. +// See freebusy_session_auth in configuration of kolab_auth plugin. +$config['calendar_freebusy_session_auth_url'] = null; + ?>
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/drivers/kolab/kolab_calendar.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/drivers/kolab/kolab_calendar.php
Changed
@@ -659,14 +659,7 @@ } // use libkolab to compute recurring events - if (class_exists('kolabcalendaring')) { - $recurrence = new kolab_date_recurrence($object); - } - else { - // fallback to local recurrence implementation - require_once($this->cal->home . '/lib/calendar_recurrence.php'); - $recurrence = new calendar_recurrence($this->cal, $event); - } + $recurrence = new kolab_date_recurrence($object); $i = 0; while ($next_event = $recurrence->next_instance()) { @@ -717,7 +710,7 @@ if (++$i > 100000) break; } - + return $events; } @@ -732,9 +725,18 @@ $record['links'] = $this->get_links($record['uid']); } - if ($this->get_namespace() == 'other') { + $ns = $this->get_namespace(); + + if ($ns == 'other') { $record['className'] = 'fc-event-ns-other'; - $record = kolab_driver::add_partstat_class($record, array('NEEDS-ACTION','DECLINED'), $this->get_owner()); + } + + if ($ns == 'other' || !$this->cal->rc->config->get('kolab_invitation_calendars')) { + $record = kolab_driver::add_partstat_class($record, array('NEEDS-ACTION', 'DECLINED'), $this->get_owner()); + + // Modify invitation status class name, when invitation calendars are disabled + // we'll use opacity only for declined/needs-action events + $record['className'] = str_replace('-invitation', '', $record['className']); } // add instance identifier to first occurrence (master event)
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/drivers/kolab/kolab_driver.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/drivers/kolab/kolab_driver.php
Changed
@@ -1157,7 +1157,7 @@ $event['end']->add(new DateInterval($new_duration)); // remove fixed weekday, will be re-set to the new weekday in kolab_calendar::update_event() - if ($old_start_date != $new_start_date) { + if ($old_start_date != $new_start_date && $event['recurrence']) { if (strlen($event['recurrence']['BYDAY']) == 2) unset($event['recurrence']['BYDAY']); if ($old['recurrence']['BYMONTH'] == $old['start']->format('n')) @@ -1784,16 +1784,16 @@ */ private function get_recurrence_count($event, $dtstart) { - // use libkolab to compute recurring events - if (class_exists('kolabcalendaring') && $event['_formatobj']) { - $recurrence = new kolab_date_recurrence($event['_formatobj']); - } - else { - // fallback to local recurrence implementation - require_once($this->cal->home . '/lib/calendar_recurrence.php'); - $recurrence = new calendar_recurrence($this->cal, $event); + // load the given event data into a libkolabxml container + if (!$event['_formatobj']) { + $event_xml = new kolab_format_event(); + $event_xml->set($event); + $event['_formatobj'] = $event_xml; } + // use libkolab to compute recurring events + $recurrence = new kolab_date_recurrence($event['_formatobj']); + $count = 0; while (($next_event = $recurrence->next_instance()) && $next_event['start'] <= $dtstart && $count < 1000) { $count++;
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/lib/calendar_ui.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/lib/calendar_ui.php
Changed
@@ -92,6 +92,7 @@ $this->cal->register_handler('plugin.resource_calendar', array($this, 'resource_calendar')); $this->cal->register_handler('plugin.attendees_freebusy_table', array($this, 'attendees_freebusy_table')); $this->cal->register_handler('plugin.edit_attendees_notify', array($this, 'edit_attendees_notify')); + $this->cal->register_handler('plugin.edit_recurrence_sync', array($this, 'edit_recurrence_sync')); $this->cal->register_handler('plugin.edit_recurring_warning', array($this, 'recurring_event_warning')); $this->cal->register_handler('plugin.event_rsvp_buttons', array($this, 'event_rsvp_buttons')); $this->cal->register_handler('plugin.angenda_options', array($this, 'angenda_options')); @@ -473,7 +474,7 @@ } /** - * + * Render HTML for attendee notification warning */ function edit_attendees_notify($attrib = array()) { @@ -482,6 +483,15 @@ } /** + * Render HTML for recurrence option to align start date with the recurrence rule + */ + function edit_recurrence_sync($attrib = array()) + { + $checkbox = new html_checkbox(array('name' => '_start_sync', 'value' => 1)); + return html::div($attrib, html::label(null, $checkbox->show(1) . ' ' . $this->cal->gettext('eventstartsync'))); + } + + /** * Generate the form for recurrence settings */ function recurring_event_warning($attrib = array())
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/localization/en_US.inc -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/localization/en_US.inc
Changed
@@ -112,6 +112,8 @@ $labels['showurl'] = 'Show calendar URL'; $labels['showurldescription'] = 'Use the following address to access (read only) your calendar from other applications. You can copy and paste this into any calendar software that supports the iCal format.'; $labels['caldavurldescription'] = 'Copy this address to a <a href="http://en.wikipedia.org/wiki/CalDAV" target="_blank">CalDAV</a> client application (e.g. Evolution or Mozilla Thunderbird) to fully synchronize this specific calendar with your computer or mobile device.'; +$labels['showfburl'] = 'Show free-busy URL'; +$labels['fburldescription'] = 'Use the following address to access Free-Busy information from other applications. You can copy and paste this into any calendar software that supports free-busy information in iCal format. No authentication is required for this URL.'; $labels['findcalendars'] = 'Find calendars...'; $labels['searchterms'] = 'Search terms'; $labels['calsearchresults'] = 'Available Calendars'; @@ -123,6 +125,7 @@ $labels['invitationsdeclined'] = 'Declined invitations'; $labels['changepartstat'] = 'Change participant status'; $labels['rsvpcomment'] = 'Invitation text'; +$labels['eventstartsync'] = 'Move the event start date to the first occurrence'; // agenda view $labels['listrange'] = 'Range to display:'; @@ -165,8 +168,6 @@ $labels['availunknown'] = 'Unknown'; $labels['availtentative'] = 'Tentative'; $labels['availoutofoffice'] = 'Out of Office'; -$labels['delegatedto'] = 'Delegated to: '; -$labels['delegatedfrom'] = 'Delegated from: '; $labels['scheduletime'] = 'Find availability'; $labels['sendinvitations'] = 'Send invitations'; $labels['sendnotifications'] = 'Notify participants about modifications'; @@ -267,6 +268,7 @@ $labels['futurevents'] = 'Future'; $labels['allevents'] = 'All'; $labels['saveasnew'] = 'Save as new'; +$labels['recurrenceerror'] = 'Unable to resolve recurrence rule for specified start date.'; // birthdays calendar $labels['birthdays'] = 'Birthdays';
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/skins/classic/calendar.css -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/skins/classic/calendar.css
Changed
@@ -1495,6 +1495,12 @@ font-weight: bold; } +.fc-needs-action, +.fc-declined, +.cal-event-status-cancelled { + opacity: 0.6; +} + .cal-event-status-cancelled .fc-event-title { text-decoration: line-through; }
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/skins/larry/calendar.css -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/skins/larry/calendar.css
Changed
@@ -433,6 +433,7 @@ background-color: #c7e3ef; } +#fburl, #calfeedurl, #caldavurl { width: 98%; @@ -794,8 +795,7 @@ } .calendarmain .eventdialog div.event-line { - margin-top: 0.1em; - margin-bottom: 0.3em; + margin-bottom: 0.4em; white-space: nowrap; overflow-x: hidden; text-overflow: ellipsis; @@ -1945,6 +1945,12 @@ font-weight: bold; } +.fc-needs-action, +.fc-declined, +.cal-event-status-cancelled { + opacity: 0.6; +} + .cal-event-status-cancelled .fc-event-title { text-decoration: line-through; } @@ -2238,6 +2244,7 @@ background-position: 2px -180px; } +#event-partstat .changersvp.unknown, #event-partstat .changersvp.needs-action, div.calendar-invitebox .rsvp-status.needs-action { background-position: 2px 0;
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/skins/larry/templates/calendar.html -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/skins/larry/templates/calendar.html
Changed
@@ -74,6 +74,9 @@ <li role="menuitem"><roundcube:button type="link" command="calendar-remove" label="calendar.removelist" classAct="active" /></li> <roundcube:endif /> <li role="menuitem"><roundcube:button type="link" command="calendar-showurl" label="calendar.showurl" classAct="active" /></li> + <roundcube:if condition="!empty(env:calendar_settings['freebusy_url'])" /> + <li role="menuitem"><roundcube:button type="link" command="calendar-showfburl" label="calendar.showfburl" classAct="active" /></li> + <roundcube:endif /> <roundcube:if condition="env:calendar_driver == 'kolab'" /> <li role="menuitem"><roundcube:button type="link" command="folders" task="settings" label="managefolders" classAct="active" /></li> <roundcube:endif /> @@ -361,6 +364,11 @@ </div> </div> +<div id="fburlbox" class="uidialog"> + <p><roundcube:label name="calendar.fburldescription" /></p> + <textarea id="fburl" rows="2" readonly="readonly"></textarea> +</div> + <roundcube:object name="plugin.calendar_css" /> <script type="text/javascript">
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/calendar/skins/larry/templates/eventedit.html -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/calendar/skins/larry/templates/eventedit.html
Changed
@@ -127,6 +127,7 @@ </div> </form> + <roundcube:object name="plugin.edit_recurrence_sync" id="edit-recurrence-syncstart" class="event-dialog-message" style="display:none" /> <roundcube:object name="plugin.edit_attendees_notify" id="edit-attendees-notify" class="event-dialog-message" style="display:none" /> <roundcube:object name="plugin.edit_recurring_warning" class="event-dialog-message edit-recurring-warning" style="display:none" /> <div id="edit-localchanges-warning" class="event-dialog-message" style="display:none"><roundcube:label name="calendar.localchangeswarning" /></div>
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_2fa/composer.json -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_2fa/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Kolab 2-Factor Authentication", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.3.0", + "version": "3.3.4", "authors": [ { "name": "Thomas Bruederli",
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_2fa/config.inc.php.dist -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_2fa/config.inc.php.dist
Changed
@@ -99,7 +99,7 @@ // $config['kolab_2fa_check'] = true; // timeout for 2nd factor auth submission (in seconds) -$config['kolab_2fa_timeout'] = 60; +$config['kolab_2fa_timeout'] = 120; // configuration parameters for TOTP (uncomment to adjust) $config['kolab_2fa_totp'] = array(
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_2fa/kolab2fa.js -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_2fa/kolab2fa.js
Changed
@@ -29,7 +29,11 @@ var highsec_call_stack = []; var highsec_dialog; var factor_dialog; - + + if (!rcmail.env.kolab_2fa_factors) { + rcmail.env.kolab_2fa_factors = {}; + } + /** * Equivalend of PHP time() */
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_2fa/kolab_2fa.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_2fa/kolab_2fa.php
Changed
@@ -459,7 +459,7 @@ } $me = $this; - $this->api->output->set_env('kolab_2fa_factors', array_combine( + $factors = array_combine( $factors, array_map(function($id) use ($me, &$env_methods) { $props = array('id' => $id); @@ -473,9 +473,10 @@ return $props; }, $factors) - )); + ); $this->api->output->set_env('kolab_2fa_methods', $env_methods); + $this->api->output->set_env('kolab_2fa_factors', !empty($factors) ? $factors : null); return html::div(array('id' => 'kolab2fapropform'), $out); } @@ -640,7 +641,10 @@ if ($success) { $this->api->output->show_message($data === false ? $this->gettext('factorremovesuccess') : $this->gettext('factorsavesuccess'), 'confirmation'); - $this->api->output->command('plugin.save_success', array('method' => $method, 'active' => $data !== false) + $save_data); + $this->api->output->command('plugin.save_success', array( + 'method' => $method, + 'active' => $data !== false, + 'id' => $driver->id) + $save_data); } else if ($errors) { $this->api->output->show_message($this->gettext('factorsaveerror'), 'error'); @@ -707,6 +711,7 @@ } } } + $success = $driver->verify(rcube_utils::get_input_value('_code', rcube_utils::INPUT_POST), $timestamp); $method = $driver->method; } @@ -722,6 +727,7 @@ 'message' => str_replace('$method', $this->gettext($method), $this->gettext($success ? 'codeverificationpassed' : 'codeverificationfailed')) )); + $this->api->output->send(); }
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_activesync/kolab_activesync_ui.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_activesync/kolab_activesync_ui.php
Changed
@@ -163,7 +163,7 @@ $names = array(); foreach ($a_folders as $folder) { - $foldername = $origname = preg_replace('/^INBOX »\s+/', '', kolab_storage::object_name($folder)); + $foldername = $origname = preg_replace('/^INBOX »\s+/', '', kolab_storage::object_prettyname($folder)); // find folder prefix to truncate (the same code as in kolab_addressbook plugin) for ($i = count($names)-1; $i >= 0; $i--) {
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_auth/composer.json -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_auth/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Kolab authentication", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.3.3", + "version": "3.3.4", "authors": [ { "name": "Thomas Bruederli",
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_auth/config.inc.php.dist -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_auth/config.inc.php.dist
Changed
@@ -88,4 +88,10 @@ // Note: special name '*' for all LDAP addressbooks $config['kolab_auth_ldap_addressbooks'] = array('*'); +// Enables storing/updating session tokens for free-busy token authentication +// See httpauth.allow_token option in Free-Busy service config. +// The option can be set to a number of seconds after which the token-session +// expires or to true (to get the configured Roundcube session time) +$config['freebusy_session_auth'] = null; + ?>
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_auth/kolab_auth.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_auth/kolab_auth.php
Changed
@@ -42,6 +42,7 @@ $this->add_hook('authenticate', array($this, 'authenticate')); $this->add_hook('startup', array($this, 'startup')); + $this->add_hook('ready', array($this, 'ready')); $this->add_hook('user_create', array($this, 'user_create')); // Hook for password change @@ -83,6 +84,69 @@ } /** + * Ready hook handler + */ + public function ready($args) + { + $rcmail = rcube::get_instance(); + + // Store user unique identifier for freebusy_session_auth feature + if (!($uniqueid = $rcmail->config->get('kolab_uniqueid'))) { + $uniqueid = $_SESSION['kolab_auth_uniqueid']; + + if (!$uniqueid) { + // Find user record in LDAP + if (($ldap = self::ldap()) && $ldap->ready) { + if ($record = $ldap->get_user_record($rcmail->get_user_name())) { + $uniqueid = $record['uniqueid']; + } + } + } + + if ($uniqueid) { + $uniqueid = md5($uniqueid); + $rcmail->user->save_prefs(array('kolab_uniqueid' => $uniqueid)); + } + } + + // Set/update freebusy_session_auth entry + if ($uniqueid && empty($_SESSION['kolab_auth_admin']) + && ($ttl = $rcmail->config->get('freebusy_session_auth')) + ) { + if ($ttl === true) { + $ttl = $rcmail->config->get('session_lifetime', 0) * 60; + + if (!$ttl) { + $ttl = 10 * 60; + } + } + + $rcmail->config->set('freebusy_auth_cache', 'db'); + $rcmail->config->set('freebusy_auth_cache_ttl', $ttl); + + if ($cache = $rcmail->get_cache_shared('freebusy_auth', false)) { + $key = md5($uniqueid . ':' . rcube_utils::remote_addr() . ':' . $rcmail->get_user_name()); + $value = $cache->get($key); + $deadline = new DateTime('now', new DateTimeZone('UTC')); + + // We don't want to do the cache update on every request + // do it once in a 1/10 of the ttl + if ($value) { + $value = new DateTime($value); + $value->sub(new DateInterval('PT' . intval($ttl * 9/10) . 'S')); + if ($value > $deadline) { + return; + } + } + + $deadline->add(new DateInterval('PT' . $ttl . 'S')); + + $cache->set($key, $deadline->format(DateTime::ISO8601)); + } + } + } + + /** * Startup hook handler */ public function startup($args) @@ -157,7 +221,7 @@ * Modifies list of plugins and settings according to * specified LDAP roles */ - public function load_user_role_plugins_and_settings() + public function load_user_role_plugins_and_settings($startup = false) { if (empty($_SESSION['user_roledns'])) { return; @@ -262,7 +326,16 @@ if (!empty($role_plugins[$role_dn])) { foreach ((array)$role_plugins[$role_dn] as $plugin) { - $this->api->load_plugin($plugin); + $loaded = $this->api->load_plugin($plugin); + + // Some plugins e.g. kolab_2fa use 'startup' hook to + // register other hooks, but when called on 'authenticate' hook + // we're already after 'startup', so we'll call it directly + if ($loaded && $startup && ($plugin = $this->api->get_plugin($plugin)) + && method_exists($plugin, 'startup') + ) { + $plugin->startup(array('task' => $rcmail->task, 'action' => $rcmail->action)); + } } } } @@ -554,6 +627,9 @@ // we don't like to use LDAP (connection + bind + search) $_SESSION['kolab_auth_vars'] = $ldap->get_parse_vars(); + // Store user unique identifier for freebusy_session_auth feature + $_SESSION['kolab_auth_uniqueid'] = is_array($record['uniqueid']) ? $record['uniqueid'][0] : $record['uniqueid']; + // Set user login if ($login_attr) { $this->data['user_login'] = is_array($record[$login_attr]) ? $record[$login_attr][0] : $record[$login_attr]; @@ -593,7 +669,7 @@ } // load per-user settings/plugins - $this->load_user_role_plugins_and_settings(); + $this->load_user_role_plugins_and_settings(true); return $args; } @@ -731,6 +807,8 @@ return null; } + $addressbook['fieldmap']['uniqueid'] = 'nsuniqueid'; + require_once __DIR__ . '/kolab_auth_ldap.php'; self::$ldap = new kolab_auth_ldap($addressbook);
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_delegation/composer.json -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_delegation/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Kolab delegation feature", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.3.2", + "version": "3.3.4", "authors": [ { "name": "Aleksander Machniak",
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_delegation/kolab_delegation.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_delegation/kolab_delegation.php
Changed
@@ -530,7 +530,7 @@ $names = array(); foreach ($a_folders as $folder) { - $foldername = $origname = preg_replace('/^INBOX »\s+/', '', kolab_storage::object_name($folder)); + $foldername = $origname = preg_replace('/^INBOX »\s+/', '', kolab_storage::object_prettyname($folder)); // find folder prefix to truncate (the same code as in kolab_addressbook plugin) for ($i = count($names)-1; $i >= 0; $i--) {
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_files/composer.json -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_files/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "User interface for Kolab File Manager (Chwala)", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.3.3", + "version": "3.3.4", "authors": [ { "name": "Aleksander Machniak",
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_files/lib/kolab_files_engine.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_files/lib/kolab_files_engine.php
Changed
@@ -992,7 +992,7 @@ protected function action_index() { $this->plugin->add_label( - 'uploading', 'attaching', 'searching', 'uploadsizeerror', + 'uploading', 'attaching', 'uploadsizeerror', 'filedeleting', 'filedeletenotice', 'filedeleteconfirm', 'filemoving', 'filemovenotice', 'filemoveconfirm', 'filecopying', 'filecopynotice', 'fileskip', 'fileskipall', 'fileoverwrite', 'fileoverwriteall' @@ -1295,37 +1295,7 @@ $attachment = $this->rc->plugins->exec_hook('attachment_save', $attachment); if ($attachment['status'] && !$attachment['abort']) { - $id = $attachment['id']; - - // store new attachment in session - unset($attachment['data'], $attachment['status'], $attachment['abort']); - $COMPOSE['attachments'][$id] = $attachment; - - if (($icon = $COMPOSE['deleteicon']) && is_file($icon)) { - $button = html::img(array( - 'src' => $icon, - 'alt' => $this->rc->gettext('delete') - )); - } - else { - $button = rcube::Q($this->rc->gettext('delete')); - } - - $content = html::a(array( - 'href' => "#delete", - 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", rcmail_output::JS_OBJECT_NAME, $id), - 'title' => $this->rc->gettext('delete'), - 'class' => 'delete', - ), $button); - - $content .= rcube::Q($attachment['name']); - - $this->rc->output->command('add2attachment_list', "rcmfile$id", array( - 'html' => $content, - 'name' => $attachment['name'], - 'mimetype' => $attachment['mimetype'], - 'classname' => rcube_utils::file2class($attachment['mimetype'], $attachment['name']), - 'complete' => true), $uploadid); + $this->compose_attach_success($attachment, $COMPOSE, $COMPOSE_ID, $uploadid); } else if ($attachment['error']) { $errors[] = $attachment['error']; @@ -1369,6 +1339,66 @@ $this->rc->output->send(); } + protected function compose_attach_success($attachment, $COMPOSE, $COMPOSE_ID, $uploadid) + { + $id = $attachment['id']; + + // store new attachment in session + unset($attachment['data'], $attachment['status'], $attachment['abort']); + $this->rc->session->append('compose_data_' . $COMPOSE_ID . '.attachments', $id, $attachment); + + if (($icon = $COMPOSE['deleteicon']) && is_file($icon)) { + $button = html::img(array( + 'src' => $icon, + 'alt' => $this->rc->gettext('delete') + )); + } + else if ($COMPOSE['textbuttons']) { + $button = rcube::Q($this->rc->gettext('delete')); + } + else { + $button = ''; + } + + if (version_compare(version_parse(RCMAIL_VERSION), '1.3.0', '>=')) { + $link_content = sprintf('%s <span class="attachment-size"> (%s)</span>', + rcube::Q($attachment['name']), $this->rc->show_bytes($attachment['size'])); + + $content_link = html::a(array( + 'href' => "#load", + 'class' => 'filename', + 'onclick' => sprintf("return %s.command('load-attachment','rcmfile%s', this, event)", rcmail_output::JS_OBJECT_NAME, $id), + ), $link_content); + + $delete_link = html::a(array( + 'href' => "#delete", + 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this, event)", rcmail_output::JS_OBJECT_NAME, $id), + 'title' => $this->rc->gettext('delete'), + 'class' => 'delete', + 'aria-label' => $this->rc->gettext('delete') . ' ' . $attachment['name'], + ), $button); + + $content = $COMPOSE['icon_pos'] == 'left' ? $delete_link.$content_link : $content_link.$delete_link; + } + else { + $content = html::a(array( + 'href' => "#delete", + 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", rcmail_output::JS_OBJECT_NAME, $id), + 'title' => $this->rc->gettext('delete'), + 'class' => 'delete', + ), $button); + + $content .= rcube::Q($attachment['name']); + } + + $this->rc->output->command('add2attachment_list', "rcmfile$id", array( + 'html' => $content, + 'name' => $attachment['name'], + 'mimetype' => $attachment['mimetype'], + 'classname' => rcube_utils::file2class($attachment['mimetype'], $attachment['name']), + 'complete' => true), $uploadid); + } + /** * Handler for file open/edit action */
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_files/localization/en_US.inc -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_files/localization/en_US.inc
Changed
@@ -23,6 +23,7 @@ $labels['folderedit'] = 'Edit folder'; $labels['foldermount'] = 'Add storage'; $labels['folderdelete'] = 'Delete folder'; +$labels['folderoptions'] = 'Folder options'; $labels['folderinside'] = 'Insert inside'; $labels['foldername'] = 'Folder name'; @@ -50,6 +51,7 @@ $labels['copyandedit'] = 'Copy and Edit'; $labels['documenttitle'] = 'Title:'; $labels['close'] = 'Close'; +$labels['docedit'] = 'Document editing'; $labels['collection_audio'] = 'Audio'; $labels['collection_video'] = 'Video'; @@ -143,9 +145,9 @@ $labels['open'] = 'Open'; $labels['request'] = 'Request an invitation'; $labels['invitationtitle'] = 'Invitation for $file'; -$labels['ivitationaccepting'] = 'Accepting an invitation...'; -$labels['ivitationdeclining'] = 'Declining an invitation...'; -$labels['ivitationrequesting'] = 'Requesting an invitation...'; +$labels['invitationaccepting'] = 'Accepting an invitation...'; +$labels['invitationdeclining'] = 'Declining an invitation...'; +$labels['invitationrequesting'] = 'Requesting an invitation...'; $labels['storepasswords'] = 'remember password'; $labels['storepasswordsdesc'] = 'Stored passwords will be encrypted. Enable this if you do not want to be asked for the password on every login or you want this storage to be available via WebDAV.'; @@ -168,6 +170,12 @@ $labels['arialabelfileprops'] = 'File properties'; $labels['arialabelfilecontent'] = 'File content'; $labels['arialabelfileeditdialog'] = 'File editing dialog'; +$labels['arialabelsessionslist'] = 'List of document editing sessions'; +$labels['arialabelfilerenameform'] = 'File rename form'; +$labels['arialabelfilesessiondialog'] = 'Document editing session'; +$labels['arialabelcollaborators'] = 'List of document editors'; +$labels['arialabelexportoptions'] = 'Export options'; +$labels['arialabeldoceditorsdialog'] = 'Document editors (invitations)'; $labels['type.plain'] = 'Plain Text Document'; $labels['type.vndoasisopendocumenttext'] = 'Text Document (ODF)';
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_tags/composer.json -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_tags/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Email tags plugin", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.3.3", + "version": "3.3.4", "authors": [ { "name": "Aleksander Machniak",
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/kolab_tags/kolab_tags.js -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/kolab_tags/kolab_tags.js
Changed
@@ -60,6 +60,17 @@ rcmail.register_command('tag-remove', function(props, obj, event) { tag_remove(props, obj, event); }); rcmail.register_command('tag-remove-all', function() { tag_remove('*'); }); + // Disable tag functionality in contextmenu in Roundcube < 1.4 + if (!rcmail.env.rcversion) { + rcmail.addEventListener('menu-open', function(e) { + if (e.name == 'rcm_markmessagemenu') { + $.each(['add', 'remove', 'remove-all'], function() { + $('a.cmd_tag-' + this).parent().hide(); + }); + } + }); + } + // ajax response handler rcmail.addEventListener('plugin.kolab_tags', update_tags);
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/libcalendaring/composer.json -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/libcalendaring/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Library providing common functions for calendaring plugins", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.3.3", + "version": "3.3.4", "authors": [ { "name": "Thomas Bruederli",
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/libcalendaring/lib/libcalendaring_itip.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/libcalendaring/lib/libcalendaring_itip.php
Changed
@@ -374,7 +374,7 @@ { $action = $event['rsvp'] ? 'rsvp' : ''; $status = $event['fallback']; - $latest = $resheduled = false; + $latest = $rescheduled = false; $html = ''; if (is_numeric($event['changed'])) @@ -404,7 +404,7 @@ if (!$latest) { // FIXME: This is probably to simplistic, or maybe we should just check // attendee's RSVP flag in the new event? - $resheduled = $existing['start'] != $event['start'] || $existing['end'] > $event['end']; + $rescheduled = $existing['start'] != $event['start'] || $existing['end'] > $event['end']; } } else { @@ -428,10 +428,16 @@ else if (!$existing && !$rsvp) { $action = 'import'; } - else if ($resheduled) { + else if ($rescheduled) { $action = 'rsvp'; } else if ($status_lc != 'needs-action') { + // check if there are any changes + if ($latest) { + $diff = $this->get_itip_diff($event, $existing); + $latest = empty($diff); + } + $action = !$latest ? 'update' : ''; } @@ -485,11 +491,69 @@ 'latest' => $latest, 'status' => $status, 'action' => $action, - 'resheduled' => $resheduled, + 'rescheduled' => $rescheduled, 'html' => $html, ); } + protected function get_itip_diff($event, $existing) + { + if (empty($event) || empty($existing) || empty($event['message_uid'])) { + return; + } + + $itip = $this->lib->mail_get_itip_object($event['mbox'], $event['message_uid'], $event['mime_id'], + $event['task'] == 'calendar' ? 'event' : 'task'); + + if ($itip) { + // List of properties that could change without SEQUENCE bump + $attrs = array('description', 'title', 'location', 'url'); + $diff = array(); + + foreach ($attrs as $attr) { + if (isset($itip[$attr]) && $itip[$attr] != $existing[$attr]) { + $diff[$attr] = array( + 'new' => $itip[$attr], + 'old' => $existing[$attr] + ); + } + } + + $status = array(); + $itip_attendees = array(); + $existing_attendees = array(); + $emails = $this->lib->get_user_emails(); + + // Compare list of attendees (ignoring current user status) + foreach ((array) $existing['attendees'] as $idx => $attendee) { + if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { + $status[strtolower($attendee['email'])] = $attendee['status']; + } + if ($attendee['role'] == 'ORGANIZER') { + $attendee['status'] = 'ACCEPTED'; // sometimes is not set for exceptions + $existing['attendees'][$idx] = $attendee; + } + $existing_attendees[] = $attendee['email'].$attendee['name']; + } + foreach ((array) $itip['attendees'] as $idx => $attendee) { + if ($attendee['email'] && ($_status = $status[strtolower($attendee['email'])])) { + $attendee['status'] = $_status; + $itip['attendees'][$idx] = $attendee; + } + $itip_attendees[] = $attendee['email'].$attendee['name']; + } + + if ($itip_attendees != $existing_attendees) { + $diff['attendees'] = array( + 'new' => $itip['attendees'], + 'old' => $existing['attendees'] + ); + } + + return $diff; + } + } + /** * Build inline UI elements for iTip messages */ @@ -508,6 +572,7 @@ 'sequence' => intval($event['sequence']), 'method' => $method, 'task' => $task, + 'mime_id' => $mime_id, ); // create buttons to be activated from async request checking existence of this event in local calendars @@ -791,11 +856,11 @@ $table->add('label', $this->gettext('recurring')); $table->add('recurrence', $this->lib->recurrence_text($event['recurrence'])); } - if ($event['location']) { + if ($event['location'] && trim($event['location'])) { $table->add('label', $this->gettext('location')); $table->add('location', rcube::Q($event['location'])); } - if ($event['sensitivity'] && $event['sensitivity'] != 'public') { + if ($event['sensitivity'] && !preg_match('/^(x-|public$)/i', $event['sensitivity'])) { $table->add('label', $this->gettext('sensitivity')); $table->add('sensitivity', ucfirst($this->gettext($event['sensitivity'])) . '!'); } @@ -803,7 +868,7 @@ $table->add('label', $this->gettext('status')); $table->add('status', $this->gettext('status-' . strtolower($event['status']))); } - if ($event['comment']) { + if ($event['comment'] && trim($event['comment'])) { $table->add('label', $this->gettext('comment')); $table->add('location', rcube::Q($event['comment'])); }
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/libcalendaring/lib/libcalendaring_recurrence.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/libcalendaring/lib/libcalendaring_recurrence.php
Changed
@@ -152,4 +152,83 @@ return $last; } + /** + * Find date/time of the first occurrence (excluding start date) + */ + public function first_occurrence() + { + $start = clone $this->start; + $orig_start = clone $this->start; + $r = $this->recurrence; + $interval = intval($r['INTERVAL'] ?: 1); + + switch ($this->recurrence['FREQ']) { + case 'WEEKLY': + if (empty($this->recurrence['BYDAY'])) { + return $start; + } + + $start->sub(new DateInterval("P{$interval}W")); + break; + + case 'MONTHLY': + if (empty($this->recurrence['BYDAY']) && empty($this->recurrence['BYMONTHDAY'])) { + return $start; + } + + $start->sub(new DateInterval("P{$interval}M")); + break; + + case 'YEARLY': + if (empty($this->recurrence['BYDAY']) && empty($this->recurrence['BYMONTH'])) { + return $start; + } + + $start->sub(new DateInterval("P{$interval}Y")); + break; + + default: + return $start; + } + + $r = $this->recurrence; + $r['INTERVAL'] = $interval; + if ($r['COUNT']) { + // Increase count so we do not stop the loop to early + $r['COUNT'] += 100; + } + + // Create recurrence that starts in the past + $recurrence = new self($this->lib); + $recurrence->init($r, $start); + + // find the first occurrence + $found = false; + while ($next = $recurrence->next()) { + $start = $next; + if ($next >= $orig_start) { + $found = true; + break; + } + } + + if (!$found) { + rcube::raise_error(array( + 'file' => __FILE__, + 'line' => __LINE__, + 'message' => sprintf("Failed to find a first occurrence. Start: %s, Recurrence: %s", + $orig_start->format(DateTime::ISO8601), json_encode($r)), + ), true); + + return null; + } + + if ($start Instanceof Horde_Date) { + $start = $start->toDateTime(); + } + + $start->_dateonly = $this->dateonly; + + return $start; + } }
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/libcalendaring/libcalendaring.js -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/libcalendaring/libcalendaring.js
Changed
@@ -1090,9 +1090,9 @@ } if (data['delegated-to']) - tooltip = rcmail.gettext('delegatedto', context) + ' ' + data['delegated-to']; + tooltip = rcmail.gettext('libcalendaring.delegatedto') + ' ' + data['delegated-to']; else if (data['delegated-from']) - tooltip = rcmail.gettext('delegatedfrom', context) + ' ' + data['delegated-from']; + tooltip = rcmail.gettext('libcalendaring.delegatedfrom') + ' ' + data['delegated-from']; return $('<span>').append( $('<span>').attr({'class': 'attendee ' + status, title: tooltip}).append(name.text(dispname)) @@ -1325,6 +1325,8 @@ */ rcube_libcalendaring.fetch_itip_object_status = function(p) { + p.mbox = rcmail.env.mailbox; + p.message_uid = rcmail.env.uid; rcmail.http_post(p.task + '/itip-status', { data: p }); }; @@ -1356,7 +1358,7 @@ $('#'+p.action+'-'+p.id).show().find('input.button').last().after(p.select); // highlight date if date change detected - if (p.resheduled) + if (p.rescheduled) $('.calendar-eventdetails td.date').addClass('modified'); // show itip box appendix after replacing the given placeholders
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/libcalendaring/libcalendaring.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/libcalendaring/libcalendaring.php
Changed
@@ -137,7 +137,7 @@ 'statusorganizer', 'statusaccepted', 'statusdeclined', 'statusdelegated', 'statusunknown', 'statusneeds-action', 'statustentative', 'statuscompleted', 'statusin-process', - 'delegatedto', 'delegatedfrom' + 'delegatedto', 'delegatedfrom', 'showmore' ); }
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/libcalendaring/localization/en_US.inc -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/libcalendaring/localization/en_US.inc
Changed
@@ -175,6 +175,8 @@ $labels['delegateto'] = 'Delegate to'; $labels['delegatersvpme'] = 'Keep me informed about updates of this incidence'; $labels['delegateinvalidaddress'] = 'Please enter a valid email address for the delegate'; +$labels['delegatedto'] = 'Delegated to:'; +$labels['delegatedfrom'] = 'Delegated from:'; $labels['savingdata'] = 'Saving data...';
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/libkolab/composer.json -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/libkolab/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Plugin to setup a basic environment for the interaction with a Kolab server.", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.3.3", + "version": "3.3.4", "authors": [ { "name": "Thomas Bruederli",
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/libkolab/lib/kolab_date_recurrence.php -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/libkolab/lib/kolab_date_recurrence.php
Changed
@@ -138,4 +138,89 @@ return false; } + + /** + * Find date/time of the first occurrence (excluding start date) + */ + public function first_occurrence() + { + $event = $this->object->to_array(); + $start = clone $this->start; + $orig_start = clone $this->start; + $interval = intval($event['recurrence']['INTERVAL'] ?: 1); + + switch ($event['recurrence']['FREQ']) { + case 'WEEKLY': + if (empty($event['recurrence']['BYDAY'])) { + return $orig_start; + } + + $start->sub(new DateInterval("P{$interval}W")); + break; + + case 'MONTHLY': + if (empty($event['recurrence']['BYDAY']) && empty($event['recurrence']['BYMONTHDAY'])) { + return $orig_start; + } + + $start->sub(new DateInterval("P{$interval}M")); + break; + + case 'YEARLY': + if (empty($event['recurrence']['BYDAY']) && empty($event['recurrence']['BYMONTH'])) { + return $orig_start; + } + + $start->sub(new DateInterval("P{$interval}Y")); + break; + + case 'DAILY': + if (!empty($event['recurrence']['BYMONTH'])) { + break; + } + + default: + return $orig_start; + } + + $event['start'] = $start; + $event['recurrence']['INTERVAL'] = $interval; + if ($event['recurrence']['COUNT']) { + // Increase count so we do not stop the loop to early + $event['recurrence']['COUNT'] += 100; + } + + // Create recurrence that starts in the past + $object_type = $this->object instanceof kolab_format_task ? 'task' : 'event'; + $object = kolab_format::factory($object_type, 3.0); + $object->set($event); + $recurrence = new self($object); + + // find the first occurrence + $found = false; + while ($next = $recurrence->next_start()) { + $start = $next; + if ($next >= $orig_start) { + $found = true; + break; + } + } + + if (!$found) { + rcube::raise_error(array( + 'file' => __FILE__, + 'line' => __LINE__, + 'message' => sprintf("Failed to find a first occurrence. Start: %s, Recurrence: %s", + $orig_start->format(DateTime::ISO8601), json_encode($event['recurrence'])), + ), true); + + return null; + } + + if ($orig_start->_dateonly) { + $start->_dateonly = true; + } + + return $start; + } }
View file
roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/libkolab/tests/kolab_date_recurrence.php
Added
@@ -0,0 +1,213 @@ +<?php + +/** + * kolab_date_recurrence tests + * + * @author Aleksander Machniak <machniak@kolabsys.com> + * + * Copyright (C) 2017, Kolab Systems AG <contact@kolabsys.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +class kolab_date_recurrence_test extends PHPUnit_Framework_TestCase +{ + function setUp() + { + $rcube = rcmail::get_instance(); + $rcube->plugins->load_plugin('libkolab', true, true); + } + + /** + * kolab_date_recurrence::first_occurrence() + * + * @dataProvider data_first_occurrence + */ + function test_first_occurrence($recurrence_data, $start, $expected) + { + $start = new DateTime($start); + if (!empty($recurrence_data['UNTIL'])) { + $recurrence_data['UNTIL'] = new DateTime($recurrence_data['UNTIL']); + } + + $event = array('start' => $start, 'recurrence' => $recurrence_data); + $object = kolab_format::factory('event', 3.0); + $object->set($event); + + $recurrence = new kolab_date_recurrence($object); + $first = $recurrence->first_occurrence(); + + $this->assertEquals($expected, $first ? $first->format('Y-m-d H:i:s') : ''); + } + + /** + * Data for test_first_occurrence() + */ + function data_first_occurrence() + { + // TODO: BYYEARDAY, BYWEEKNO, BYSETPOS, WKST + + return array( + // non-recurring + array( + array(), // recurrence data + '2017-08-31 11:00:00', // start date + '2017-08-31 11:00:00', // expected result + ), + // daily + array( + array('FREQ' => 'DAILY', 'INTERVAL' => '1'), // recurrence data + '2017-08-31 11:00:00', // start date + '2017-08-31 11:00:00', // expected result + ), + // TODO: this one is not supported by the Calendar UI + array( + array('FREQ' => 'DAILY', 'INTERVAL' => '1', 'BYMONTH' => 1), + '2017-08-31 11:00:00', + '2018-01-01 11:00:00', + ), + // weekly + array( + array('FREQ' => 'WEEKLY', 'INTERVAL' => '1'), + '2017-08-31 11:00:00', // Thursday + '2017-08-31 11:00:00', + ), + array( + array('FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'WE'), + '2017-08-31 11:00:00', // Thursday + '2017-09-06 11:00:00', + ), + array( + array('FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'TH'), + '2017-08-31 11:00:00', // Thursday + '2017-08-31 11:00:00', + ), + array( + array('FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'FR'), + '2017-08-31 11:00:00', // Thursday + '2017-09-01 11:00:00', + ), + array( + array('FREQ' => 'WEEKLY', 'INTERVAL' => '2'), + '2017-08-31 11:00:00', // Thursday + '2017-08-31 11:00:00', + ), + array( + array('FREQ' => 'WEEKLY', 'INTERVAL' => '3', 'BYDAY' => 'WE'), + '2017-08-31 11:00:00', // Thursday + '2017-09-20 11:00:00', + ), + array( + array('FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'WE', 'COUNT' => 1), + '2017-08-31 11:00:00', // Thursday + '2017-09-06 11:00:00', + ), + array( + array('FREQ' => 'WEEKLY', 'INTERVAL' => '1', 'BYDAY' => 'WE', 'UNTIL' => '2017-09-01'), + '2017-08-31 11:00:00', // Thursday + '', + ), + // monthly + array( + array('FREQ' => 'MONTHLY', 'INTERVAL' => '1'), + '2017-09-08 11:00:00', + '2017-09-08 11:00:00', + ), + array( + array('FREQ' => 'MONTHLY', 'INTERVAL' => '1', 'BYMONTHDAY' => '8,9'), + '2017-08-31 11:00:00', + '2017-09-08 11:00:00', + ), + array( + array('FREQ' => 'MONTHLY', 'INTERVAL' => '1', 'BYMONTHDAY' => '8,9'), + '2017-09-08 11:00:00', + '2017-09-08 11:00:00', + ), + array( + array('FREQ' => 'MONTHLY', 'INTERVAL' => '1', 'BYDAY' => '1WE'), + '2017-08-16 11:00:00', + '2017-09-06 11:00:00', + ), + array( + array('FREQ' => 'MONTHLY', 'INTERVAL' => '1', 'BYDAY' => '-1WE'), + '2017-08-16 11:00:00', + '2017-08-30 11:00:00', + ), + array( + array('FREQ' => 'MONTHLY', 'INTERVAL' => '2'), + '2017-09-08 11:00:00', + '2017-09-08 11:00:00', + ), + array( + array('FREQ' => 'MONTHLY', 'INTERVAL' => '2', 'BYMONTHDAY' => '8'), + '2017-08-31 11:00:00', + '2017-09-08 11:00:00', // ?????? + ), + // yearly + array( + array('FREQ' => 'YEARLY', 'INTERVAL' => '1'), + '2017-08-16 11:00:00', + '2017-08-16 11:00:00', + ), + array( + array('FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYMONTH' => '8'), + '2017-08-16 11:00:00', + '2017-08-16 11:00:00', + ), + array( + array('FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYDAY' => '-1MO'), + '2017-08-16 11:00:00', + '2017-12-25 11:00:00', + ), + array( + array('FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYMONTH' => '8', 'BYDAY' => '-1MO'), + '2017-08-16 11:00:00', + '2017-08-28 11:00:00', + ), + array( + array('FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYMONTH' => '1', 'BYDAY' => '1MO'), + '2017-08-16 11:00:00', + '2018-01-01 11:00:00', + ), + array( + array('FREQ' => 'YEARLY', 'INTERVAL' => '1', 'BYMONTH' => '1,9', 'BYDAY' => '1MO'), + '2017-08-16 11:00:00', + '2017-09-04 11:00:00', + ), + array( + array('FREQ' => 'YEARLY', 'INTERVAL' => '2'), + '2017-08-16 11:00:00', + '2017-08-16 11:00:00', + ), + array( + array('FREQ' => 'YEARLY', 'INTERVAL' => '2', 'BYMONTH' => '8'), + '2017-08-16 11:00:00', + '2017-08-16 11:00:00', + ), + array( + array('FREQ' => 'YEARLY', 'INTERVAL' => '2', 'BYDAY' => '-1MO'), + '2017-08-16 11:00:00', + '2017-12-25 11:00:00', + ), + // on dates (FIXME: do we really expect the first occurrence to be on the start date?) + array( + array('RDATE' => array (new DateTime('2017-08-10 11:00:00 Europe/Warsaw'))), + '2017-08-01 11:00:00', + '2017-08-01 11:00:00', + ), + ); + } + +} +
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/tasklist/composer.json -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/tasklist/composer.json
Changed
@@ -4,7 +4,7 @@ "description": "Task management plugin", "homepage": "https://git.kolab.org/diffusion/RPK/", "license": "AGPLv3", - "version": "3.3.3", + "version": "3.3.4", "authors": [ { "name": "Thomas Bruederli",
View file
roundcubemail-plugins-kolab-3.3.3.tar.gz/plugins/tasklist/localization/en_US.inc -> roundcubemail-plugins-kolab-3.3.4.tar.gz/plugins/tasklist/localization/en_US.inc
Changed
@@ -197,8 +197,6 @@ $labels['delegateinvitation'] = 'Delegate assignment'; $labels['andnmore'] = '$nr more...'; -$labels['delegatedto'] = 'Delegated to: '; -$labels['delegatedfrom'] = 'Delegated from: '; $labels['savetotasklist'] = 'Save to tasks'; $labels['comment'] = 'Comment'; $labels['errorimportingtask'] = 'Failed to import task(s)';
View file
roundcubemail-plugins-kolab.dsc
Changed
@@ -2,7 +2,7 @@ Source: roundcubemail-plugins-kolab Binary: roundcubemail-plugins-kolab Architecture: all -Version: 1:3.3.3-0~kolab1 +Version: 1:3.3.4-0~kolab2 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Paul Klos <kolab@klos2day.nl> Standards-Version: 3.9.3 @@ -34,5 +34,5 @@ roundcubemail-plugin-tinymce-config deb web extra roundcubemail-plugin-wap-client deb web extra Files: - 00000000000000000000000000000000 0 roundcubemail-plugins-kolab-3.3.3.tar.gz + 00000000000000000000000000000000 0 roundcubemail-plugins-kolab-3.3.4.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.