Adapt to new timezone handling in Roundcube core; provide direct url to subscribe to calendars (using http auth)
This commit is contained in:
parent
210edef7dc
commit
ee77665dd5
9 changed files with 135 additions and 23 deletions
|
@ -38,6 +38,7 @@ class calendar extends rcube_plugin
|
|||
public $home; // declare public to be used in other classes
|
||||
public $urlbase;
|
||||
public $timezone;
|
||||
public $timezone_offset;
|
||||
public $gmt_offset;
|
||||
|
||||
public $ical;
|
||||
|
@ -96,10 +97,11 @@ class calendar extends rcube_plugin
|
|||
$this->add_texts('localization/', $this->rc->task == 'calendar' && (!$this->rc->action || $this->rc->action == 'print'));
|
||||
|
||||
// set user's timezone
|
||||
$this->timezone = $this->rc->config->get('timezone');
|
||||
$this->dst_active = $this->rc->config->get('dst_active');
|
||||
$this->gmt_offset = ($this->timezone + $this->dst_active) * 3600;
|
||||
$this->user_timezone = new DateTimeZone($this->timezone ? timezone_name_from_abbr("", $this->gmt_offset, $this->dst_active) : 'GMT');
|
||||
$this->timezone = new DateTimeZone($this->rc->config->get('timezone', 'GMT'));
|
||||
$now = new DateTime('now', $this->timezone);
|
||||
$this->timezone_offset = $now->format('Z') / 3600;
|
||||
$this->dst_active = $now->format('I');
|
||||
$this->gmt_offset = $now->getOffset();
|
||||
|
||||
require($this->home . '/lib/calendar_ui.php');
|
||||
$this->ui = new calendar_ui($this);
|
||||
|
@ -119,6 +121,9 @@ class calendar extends rcube_plugin
|
|||
if ($this->rc->action == 'attend' && !empty($_REQUEST['_t'])) {
|
||||
$this->add_hook('startup', array($this, 'itip_attend_response'));
|
||||
}
|
||||
else if ($this->rc->action == 'feed' && !empty($_REQUEST['_cal'])) {
|
||||
$this->add_hook('startup', array($this, 'ical_feed_export'));
|
||||
}
|
||||
else if ($this->rc->task == 'calendar' && $this->rc->action != 'save-pref') {
|
||||
if ($this->rc->action != 'upload') {
|
||||
$this->load_driver();
|
||||
|
@ -890,7 +895,7 @@ class calendar extends rcube_plugin
|
|||
/**
|
||||
* Construct the ics file for exporting events to iCalendar format;
|
||||
*/
|
||||
function export_events()
|
||||
function export_events($terminate = true)
|
||||
{
|
||||
$start = get_input_value('start', RCUBE_INPUT_GET);
|
||||
$end = get_input_value('end', RCUBE_INPUT_GET);
|
||||
|
@ -903,14 +908,73 @@ class calendar extends rcube_plugin
|
|||
$calname = $calendars[$calid]['name'] ? $calendars[$calid]['name'] : $calid;
|
||||
$events = $this->driver->load_events($start, $end, null, $calid, 0);
|
||||
}
|
||||
else
|
||||
$events = array();
|
||||
|
||||
header("Content-Type: text/calendar");
|
||||
header("Content-Disposition: inline; filename=".$calname.'.ics');
|
||||
|
||||
$this->get_ical()->export($events, '', true);
|
||||
|
||||
if ($terminate)
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handler for iCal feed requests
|
||||
*/
|
||||
function ical_feed_export()
|
||||
{
|
||||
// process HTTP auth info
|
||||
if (!empty($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
|
||||
$_POST['_user'] = $_SERVER['PHP_AUTH_USER']; // used for rcmail::autoselect_host()
|
||||
$auth = $this->rc->plugins->exec_hook('authenticate', array(
|
||||
'host' => $this->rc->autoselect_host(),
|
||||
'user' => trim($_SERVER['PHP_AUTH_USER']),
|
||||
'pass' => $_SERVER['PHP_AUTH_PW'],
|
||||
'cookiecheck' => true,
|
||||
'valid' => true,
|
||||
));
|
||||
if ($auth['valid'] && !$auth['abort'])
|
||||
$this->rc->login($auth['user'], $auth['pass'], $auth['host']);
|
||||
}
|
||||
|
||||
// require HTTP auth
|
||||
if (empty($_SESSION['user_id'])) {
|
||||
header('WWW-Authenticate: Basic realm="Roundcube Calendar"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
exit;
|
||||
}
|
||||
|
||||
// decode calendar feed hash
|
||||
$format = 'ics';
|
||||
$calhash = get_input_value('_cal', RCUBE_INPUT_GET);
|
||||
if (preg_match(($suff_regex = '/\.([a-z0-9]{3,5})$/i'), $calhash, $m)) {
|
||||
$format = strtolower($m[1]);
|
||||
$calhash = preg_replace($suff_regex, '', $calhash);
|
||||
}
|
||||
|
||||
if (!strpos($calhash, ':'))
|
||||
$calhash = base64_decode($calhash);
|
||||
|
||||
list($user, $_GET['source']) = explode(':', $calhash, 2);
|
||||
|
||||
// sanity check user
|
||||
if ($this->rc->user->get_username() == $user) {
|
||||
$this->load_driver();
|
||||
$this->export_events(false);
|
||||
}
|
||||
else {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
}
|
||||
|
||||
// don't save session data
|
||||
session_destroy();
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -939,7 +1003,7 @@ class calendar extends rcube_plugin
|
|||
$settings['agenda_sections'] = $this->rc->config->get('calendar_agenda_sections', $this->defaults['calendar_agenda_sections']);
|
||||
$settings['event_coloring'] = (int)$this->rc->config->get('calendar_event_coloring', $this->defaults['calendar_event_coloring']);
|
||||
$settings['time_indicator'] = (int)$this->rc->config->get('calendar_time_indicator', $this->defaults['calendar_time_indicator']);
|
||||
$settings['timezone'] = $this->timezone;
|
||||
$settings['timezone'] = $this->timezone_offset;
|
||||
$settings['dst'] = $this->dst_active;
|
||||
|
||||
// localization
|
||||
|
@ -1661,8 +1725,8 @@ class calendar extends rcube_plugin
|
|||
}
|
||||
|
||||
// add timezone information
|
||||
if ($tzinfo && ($tzname = $this->user_timezone->getName())) {
|
||||
$fromto .= ' (' . $tzname . ')';
|
||||
if ($tzinfo && ($tzname = $this->timezone->getName())) {
|
||||
$fromto .= ' (' . strtr($tzname, '_', ' ') . ')';
|
||||
}
|
||||
|
||||
return $fromto;
|
||||
|
@ -2311,4 +2375,10 @@ class calendar extends rcube_plugin
|
|||
return $url;
|
||||
}
|
||||
|
||||
|
||||
public function ical_feed_hash($source)
|
||||
{
|
||||
return base64_encode($this->rc->user->get_username() . ':' . $source);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1953,6 +1953,26 @@ function rcube_calendar_ui(settings)
|
|||
this.refresh(p);
|
||||
};
|
||||
|
||||
// show URL of the given calendar in a dialog box
|
||||
this.showurl = function(calendar)
|
||||
{
|
||||
var $dialog = $('#calendarurlbox').dialog('close');
|
||||
|
||||
if (calendar.feedurl) {
|
||||
$dialog.dialog({
|
||||
resizable: true,
|
||||
closeOnEscape: true,
|
||||
title: rcmail.gettext('showurl', 'calendar'),
|
||||
close: function() {
|
||||
$dialog.dialog("destroy").hide();
|
||||
},
|
||||
width: 520
|
||||
}).show();
|
||||
|
||||
$('#calfeedurl').val(calendar.feedurl).select();
|
||||
}
|
||||
};
|
||||
|
||||
// refresh the calendar view after saving event data
|
||||
this.refresh = function(p)
|
||||
{
|
||||
|
@ -2183,7 +2203,7 @@ function rcube_calendar_ui(settings)
|
|||
var id = $(this).data('id');
|
||||
rcmail.select_folder(id, 'rcmlical');
|
||||
rcmail.enable_command('calendar-edit', true);
|
||||
rcmail.enable_command('calendar-remove', 'events-import', !me.calendars[id].readonly);
|
||||
rcmail.enable_command('calendar-remove', 'events-import', 'calendar-showurl', !me.calendars[id].readonly);
|
||||
me.selected_calendar = id;
|
||||
})
|
||||
.dblclick(function(){ me.calendar_edit_dialog(me.calendars[me.selected_calendar]); })
|
||||
|
@ -2673,6 +2693,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
|
|||
rcmail.register_command('calendar-edit', function(){ cal.calendar_edit_dialog(cal.calendars[cal.selected_calendar]); }, false);
|
||||
rcmail.register_command('calendar-remove', function(){ cal.calendar_remove(cal.calendars[cal.selected_calendar]); }, false);
|
||||
rcmail.register_command('events-import', function(){ cal.import_events(cal.calendars[cal.selected_calendar]); }, false);
|
||||
rcmail.register_command('calendar-showurl', function(){ cal.showurl(cal.calendars[cal.selected_calendar]); }, false);
|
||||
|
||||
// search and export events
|
||||
rcmail.register_command('export', function(){ rcmail.goto_url('export_events', { source:cal.selected_calendar }); }, true);
|
||||
|
|
|
@ -40,7 +40,6 @@ class calendar_ical
|
|||
|
||||
private $rc;
|
||||
private $cal;
|
||||
private $timezone = 'Z';
|
||||
|
||||
public $method;
|
||||
public $events = array();
|
||||
|
@ -49,12 +48,6 @@ class calendar_ical
|
|||
{
|
||||
$this->cal = $cal;
|
||||
$this->rc = $cal->rc;
|
||||
|
||||
// compose timezone string
|
||||
if ($cal->timezone) {
|
||||
$hours = floor($cal->timezone + $cal->dst_active);
|
||||
$this->timezone = sprintf('%s%02d:%02d', ($hours >= 0 ? '+' : ''), $hours, ($cal->timezone - $hours) * 60);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -313,7 +306,12 @@ class calendar_ical
|
|||
private function _date2time($prop)
|
||||
{
|
||||
// create timestamp at 12:00 in user's timezone
|
||||
return is_array($prop) ? strtotime(sprintf('%04d%02d%02dT120000%s', $prop['year'], $prop['month'], $prop['mday'], $this->timezone)) : $prop;
|
||||
if (is_array($prop)) {
|
||||
$date = new DateTime(sprintf('%04d%02d%02dT120000', $prop['year'], $prop['month'], $prop['mday']), $this->cal->timezone);
|
||||
console($prop, $date->format('r'));
|
||||
return $date->getTimestamp();
|
||||
}
|
||||
return $prop;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,11 +48,11 @@ class calendar_ui
|
|||
|
||||
// add taskbar button
|
||||
$this->cal->add_button(array(
|
||||
'name' => 'calendar',
|
||||
'command' => 'calendar',
|
||||
'class' => 'button-calendar',
|
||||
'classsel' => 'button-calendar button-selected',
|
||||
'innerclass' => 'button-inner',
|
||||
'label' => 'calendar.calendar',
|
||||
'href' => './?_task=calendar',
|
||||
'onclick' => sprintf("%s.command('plugin.calendar');return false", JS_OBJECT_NAME),
|
||||
), 'taskbar');
|
||||
|
||||
// load basic client script (which - unfortunately - requires fullcalendar)
|
||||
|
@ -191,6 +191,7 @@ class calendar_ui
|
|||
$prop['freebusy'] = $this->cal->driver->freebusy;
|
||||
$prop['attachments'] = $this->cal->driver->attachments;
|
||||
$prop['undelete'] = $this->cal->driver->undelete;
|
||||
$prop['feedurl'] = $this->cal->get_url(array('_cal' => $this->cal->ical_feed_hash($id) . '.ics', 'action' => 'feed'));
|
||||
$jsenv[$id] = $prop;
|
||||
|
||||
$html_id = html_identifier($id);
|
||||
|
|
|
@ -72,6 +72,8 @@ $labels['importevents'] = 'Termine importieren';
|
|||
$labels['importrange'] = 'Termine ab';
|
||||
$labels['onemonthback'] = '1 Monat zurück';
|
||||
$labels['nmonthsback'] = '$nr Monate zurück';
|
||||
$labels['showurl'] = 'URL anzeigen';
|
||||
$labels['showurldescription'] = 'Über die folgende Adresse können Sie mit einem beliebigen Kalenderprogramm auf Ihren Kalender zugreifen, sofern dieses das iCal-Format unterstützt.';
|
||||
|
||||
// agenda view
|
||||
$labels['listrange'] = 'Angezeigter Bereich:';
|
||||
|
|
|
@ -72,6 +72,8 @@ $labels['importevents'] = 'Termine importieren';
|
|||
$labels['importrange'] = 'Termine ab';
|
||||
$labels['onemonthback'] = '1 Monat zurück';
|
||||
$labels['nmonthsback'] = '$nr Monate zurück';
|
||||
$labels['showurl'] = 'URL anzeigen';
|
||||
$labels['showurldescription'] = 'Über die folgende Adresse können Sie mit einem beliebigen Kalenderprogramm auf Ihren Kalender zugreifen, sofern dieses das iCal-Format unterstützt.';
|
||||
|
||||
// agenda view
|
||||
$labels['listrange'] = 'Angezeigter Bereich:';
|
||||
|
|
|
@ -72,6 +72,8 @@ $labels['importevents'] = 'Import events';
|
|||
$labels['importrange'] = 'Events from';
|
||||
$labels['onemonthback'] = '1 month back';
|
||||
$labels['nmonthsback'] = '$nr months back';
|
||||
$labels['showurl'] = 'Show calendar URL';
|
||||
$labels['showurldescription'] = 'Use the following address to access your calendar from other applications. You can copy and paste this into any calendar software that supports the iCal format.';
|
||||
|
||||
// agenda view
|
||||
$labels['listrange'] = 'Range to display:';
|
||||
|
|
|
@ -162,6 +162,14 @@ pre {
|
|||
background-position: 0 -92px;
|
||||
}
|
||||
|
||||
#calfeedurl {
|
||||
width: 98%;
|
||||
background: #fbfbfb;
|
||||
padding: 4px;
|
||||
margin-bottom: 1em;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
#agendalist {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
|
@ -1164,7 +1172,9 @@ fieldset #calendarcategories div {
|
|||
/* Invitation UI in mail */
|
||||
|
||||
#messagemenu li a.calendarlink {
|
||||
background: url(images/calendars.png) 7px -109px no-repeat;
|
||||
background-image: url(images/calendars.png);
|
||||
background-position: 7px -109px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
div.calendar-invitebox {
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
<li><roundcube:button command="calendar-edit" label="calendar.edit" classAct="active" /></li>
|
||||
<li><roundcube:button command="calendar-remove" label="calendar.remove" classAct="active" /></li>
|
||||
<li><roundcube:button command="events-import" label="calendar.importevents" classAct="active" /></li>
|
||||
<li><roundcube:button command="calendar-showurl" label="calendar.showurl" classAct="active" /></li>
|
||||
<roundcube:if condition="env:calendar_driver == 'kolab'" />
|
||||
<li class="separator_above"><roundcube:button command="folders" task="settings" type="link" label="managefolders" classAct="active" /></li>
|
||||
<roundcube:endif />
|
||||
|
@ -142,6 +143,11 @@
|
|||
<roundcube:object name="plugin.events_import_form" id="events-import-form" uploadFieldSize="30" />
|
||||
</div>
|
||||
|
||||
<div id="calendarurlbox" class="uidialog">
|
||||
<p><roundcube:label name="calendar.showurldescription" /></p>
|
||||
<textarea id="calfeedurl" rows="2" readonly="readonly"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="alarm-snooze-dropdown" class="popupmenu">
|
||||
<roundcube:object name="plugin.snooze_select" type="ul" />
|
||||
</div>
|
||||
|
|
Loading…
Add table
Reference in a new issue