- Move attachment handling functions to libcalendaring module.

- Removed redundant code in calendar and tasklist
- Add more vertical space in attachment view window
- Minor bugfixes
This commit is contained in:
Thomas Bruederli 2012-08-16 19:03:17 +02:00
parent 9b2c795391
commit d919e2b4bd
15 changed files with 331 additions and 477 deletions

View file

@ -31,7 +31,9 @@ class calendar extends rcube_plugin
const FREEBUSY_BUSY = 2;
const FREEBUSY_TENTATIVE = 3;
const FREEBUSY_OOF = 4;
const SESSION_KEY = 'calendar_temp';
public $task = '?(?!logout).*';
public $rc;
public $lib;
@ -1193,106 +1195,7 @@ class calendar extends rcube_plugin
*/
public function attachment_upload()
{
// Upload progress update
if (!empty($_GET['_progress'])) {
rcube_upload_progress();
}
$event = get_input_value('_id', RCUBE_INPUT_GPC);
$uploadid = get_input_value('_uploadid', RCUBE_INPUT_GPC);
$eventid = 'cal:'.$event;
if (!is_array($_SESSION['event_session']) || $_SESSION['event_session']['id'] != $eventid) {
$_SESSION['event_session'] = array();
$_SESSION['event_session']['id'] = $eventid;
$_SESSION['event_session']['attachments'] = array();
}
// clear all stored output properties (like scripts and env vars)
$this->rc->output->reset();
if (is_array($_FILES['_attachments']['tmp_name'])) {
foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
// Process uploaded attachment if there is no error
$err = $_FILES['_attachments']['error'][$i];
if (!$err) {
$attachment = array(
'path' => $filepath,
'size' => $_FILES['_attachments']['size'][$i],
'name' => $_FILES['_attachments']['name'][$i],
'mimetype' => rc_mime_content_type($filepath, $_FILES['_attachments']['name'][$i], $_FILES['_attachments']['type'][$i]),
'group' => $eventid,
);
$attachment = $this->rc->plugins->exec_hook('attachment_upload', $attachment);
}
if (!$err && $attachment['status'] && !$attachment['abort']) {
$id = $attachment['id'];
// store new attachment in session
unset($attachment['status'], $attachment['abort']);
$_SESSION['event_session']['attachments'][$id] = $attachment;
if (($icon = $_SESSION['calendar_deleteicon']) && is_file($icon)) {
$button = html::img(array(
'src' => $icon,
'alt' => rcube_label('delete')
));
}
else {
$button = Q(rcube_label('delete'));
}
$content = html::a(array(
'href' => "#delete",
'class' => 'delete',
'onclick' => sprintf("return %s.remove_from_attachment_list('rcmfile%s')", JS_OBJECT_NAME, $id),
'title' => rcube_label('delete'),
), $button);
$content .= Q($attachment['name']);
$this->rc->output->command('add2attachment_list', "rcmfile$id", array(
'html' => $content,
'name' => $attachment['name'],
'mimetype' => $attachment['mimetype'],
'classname' => rcmail_filetype2classname($attachment['mimetype'], $attachment['name']),
'complete' => true), $uploadid);
}
else { // upload failed
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
$msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array(
'size' => show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
}
else if ($attachment['error']) {
$msg = $attachment['error'];
}
else {
$msg = rcube_label('fileuploaderror');
}
$this->rc->output->command('display_message', $msg, 'error');
$this->rc->output->command('remove_from_attachment_list', $uploadid);
}
}
}
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// if filesize exceeds post_max_size then $_FILES array is empty,
// show filesizeerror instead of fileuploaderror
if ($maxsize = ini_get('post_max_size'))
$msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array(
'size' => show_bytes(parse_bytes($maxsize)))));
else
$msg = rcube_label('fileuploaderror');
$this->rc->output->command('display_message', $msg, 'error');
$this->rc->output->command('remove_from_attachment_list', $uploadid);
}
$this->rc->output->send('iframe');
$this->lib->attachment_upload(self::SESSION_KEY, 'cal:');
}
/**
@ -1300,102 +1203,29 @@ class calendar extends rcube_plugin
*/
public function attachment_get()
{
$event = get_input_value('_event', RCUBE_INPUT_GPC);
// show loading page
if (!empty($_GET['_preload'])) {
return $this->lib->attachment_loading_page();
}
$event_id = get_input_value('_event', RCUBE_INPUT_GPC);
$calendar = get_input_value('_cal', RCUBE_INPUT_GPC);
$id = get_input_value('_id', RCUBE_INPUT_GPC);
$event = array('id' => $event, 'calendar' => $calendar);
// show loading page
if (!empty($_GET['_preload'])) {
$url = str_replace('&_preload=1', '', $_SERVER['REQUEST_URI']);
$message = rcube_label('loadingdata');
header('Content-Type: text/html; charset=' . RCMAIL_CHARSET);
print "<html>\n<head>\n"
. '<meta http-equiv="refresh" content="0; url='.Q($url).'">' . "\n"
. '<meta http-equiv="content-type" content="text/html; charset='.RCMAIL_CHARSET.'">' . "\n"
. "</head>\n<body>\n$message\n</body>\n</html>";
exit;
}
ob_end_clean();
$attachment = $GLOBALS['calendar_attachment'] = $this->driver->get_attachment($id, $event);
$event = array('id' => $event_id, 'calendar' => $calendar);
$attachment = $this->driver->get_attachment($id, $event);
// show part page
if (!empty($_GET['_frame'])) {
$this->attachment = $attachment;
$this->register_handler('plugin.attachmentframe', array($this, 'attachment_frame'));
$this->register_handler('plugin.attachmentcontrols', array($this->ui, 'attachment_controls'));
$this->rc->output->send('calendar.attachment');
exit;
$this->lib->attachment = $attachment;
$this->register_handler('plugin.attachmentframe', array($this->lib, 'attachment_frame'));
$this->register_handler('plugin.attachmentcontrols', array($this->lib, 'attachment_header'));
$this->rc->output->send('calendar.attachment');
}
if ($attachment) {
// allow post-processing of the attachment body
$part = new rcube_message_part;
$part->filename = $attachment['name'];
$part->size = $attachment['size'];
$part->mimetype = $attachment['mimetype'];
$plugin = $this->rc->plugins->exec_hook('message_part_get', array(
'body' => $this->driver->get_attachment_body($id, $event),
'mimetype' => strtolower($attachment['mimetype']),
'download' => !empty($_GET['_download']),
'part' => $part,
));
if ($plugin['abort'])
exit;
$mimetype = $plugin['mimetype'];
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
$browser = $this->rc->output->browser;
// send download headers
if ($plugin['download']) {
header("Content-Type: application/octet-stream");
if ($browser->ie)
header("Content-Type: application/force-download");
}
else if ($ctype_primary == 'text') {
header("Content-Type: text/$ctype_secondary");
}
else {
// $mimetype = rcmail_fix_mimetype($mimetype);
header("Content-Type: $mimetype");
header("Content-Transfer-Encoding: binary");
}
// display page, @TODO: support text/plain (and maybe some other text formats)
if ($mimetype == 'text/html' && empty($_GET['_download'])) {
$OUTPUT = new rcube_html_page();
// @TODO: use washtml on $body
$OUTPUT->write($plugin['body']);
}
else {
// don't kill the connection if download takes more than 30 sec.
@set_time_limit(0);
$filename = $attachment['name'];
$filename = preg_replace('[\r\n]', '', $filename);
if ($browser->ie && $browser->ver < 7)
$filename = rawurlencode(abbreviate_string($filename, 55));
else if ($browser->ie)
$filename = rawurlencode($filename);
else
$filename = addcslashes($filename, '"');
$disposition = !empty($_GET['_download']) ? 'attachment' : 'inline';
header("Content-Disposition: $disposition; filename=\"$filename\"");
echo $plugin['body'];
}
exit;
// deliver attachment content
else if ($attachment) {
$attachment['body'] = $this->driver->get_attachment_body($id, $event);
$this->lib->attachment_get($attachment);
}
// if we arrive here, the requested part was not found
@ -1403,20 +1233,6 @@ class calendar extends rcube_plugin
exit;
}
/**
* Template object for attachment display frame
*/
public function attachment_frame($attrib)
{
$attachment = $GLOBALS['calendar_attachment'];
$mimetype = strtolower($attachment['mimetype']);
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
$attrib['src'] = './?' . str_replace('_frame=', ($ctype_primary == 'text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']);
return html::iframe($attrib);
}
/**
* Prepares new/edited event properties before save
@ -1432,9 +1248,9 @@ class calendar extends rcube_plugin
$attachments = array();
$eventid = 'cal:'.$event['id'];
if (is_array($_SESSION['event_session']) && $_SESSION['event_session']['id'] == $eventid) {
if (!empty($_SESSION['event_session']['attachments'])) {
foreach ($_SESSION['event_session']['attachments'] as $id => $attachment) {
if (is_array($_SESSION[self::SESSION_KEY]) && $_SESSION[self::SESSION_KEY]['id'] == $eventid) {
if (!empty($_SESSION[self::SESSION_KEY]['attachments'])) {
foreach ($_SESSION[self::SESSION_KEY]['attachments'] as $id => $attachment) {
if (is_array($event['attachments']) && in_array($id, $event['attachments'])) {
$attachments[$id] = $this->rc->plugins->exec_hook('attachment_get', $attachment);
}
@ -1474,9 +1290,9 @@ class calendar extends rcube_plugin
private function cleanup_event(&$event)
{
// remove temp. attachment files
if (!empty($_SESSION['event_session']) && ($eventid = $_SESSION['event_session']['id'])) {
if (!empty($_SESSION[self::SESSION_KEY]) && ($eventid = $_SESSION[self::SESSION_KEY]['id'])) {
$this->rc->plugins->exec_hook('attachments_cleanup', array('group' => $eventid));
$this->rc->session->remove('event_session');
$this->rc->session->remove(self::SESSION_KEY);
}
}
@ -2089,10 +1905,10 @@ class calendar extends rcube_plugin
// copy mail attachments to event
if ($message->attachments) {
$eventid = 'cal:';
if (!is_array($_SESSION['event_session']) || $_SESSION['event_session']['id'] != $eventid) {
$_SESSION['event_session'] = array();
$_SESSION['event_session']['id'] = $eventid;
$_SESSION['event_session']['attachments'] = array();
if (!is_array($_SESSION[self::SESSION_KEY]) || $_SESSION[self::SESSION_KEY]['id'] != $eventid) {
$_SESSION[self::SESSION_KEY] = array();
$_SESSION[self::SESSION_KEY]['id'] = $eventid;
$_SESSION[self::SESSION_KEY]['attachments'] = array();
}
foreach ((array)$message->attachments as $part) {
@ -2112,7 +1928,7 @@ class calendar extends rcube_plugin
// store new attachment in session
unset($attachment['status'], $attachment['abort'], $attachment['data']);
$_SESSION['event_session']['attachments'][$id] = $attachment;
$_SESSION[self::SESSION_KEY]['attachments'][$id] = $attachment;
$attachment['id'] = 'rcmfile' . $attachment['id']; # add prefix to consider it 'new'
$event['attachments'][] = $attachment;

View file

@ -680,7 +680,7 @@ class kolab_driver extends calendar_driver
foreach ($calendar->list_events($time, $time + 86400 * 365, null, 1, $query) as $e) {
// add to list if alarm is set
$alarm = calendarlibcalendaring::get_next_alarm($e);
$alarm = libcalendaring::get_next_alarm($e);
if ($alarm && $alarm['time'] && $alarm['time'] <= $time && $alarm['action'] == 'DISPLAY') {
$id = $e['id'];
$events[$id] = $e;

View file

@ -595,7 +595,7 @@ class calendar_ui
$skin_path = $this->cal->local_skin_path();
if ($attrib['deleteicon']) {
$_SESSION['calendar_deleteicon'] = $skin_path . $attrib['deleteicon'];
$_SESSION[calendar::SESSION_KEY . '_deleteicon'] = $skin_path . $attrib['deleteicon'];
$this->rc->output->set_env('deleteicon', $skin_path . $attrib['deleteicon']);
}
if ($attrib['cancelicon'])
@ -608,24 +608,6 @@ class calendar_ui
return html::tag('ul', $attrib, '', html::$common_attrib);
}
function attachment_controls($attrib = array())
{
$table = new html_table(array('cols' => 3));
if (!empty($this->cal->attachment['name'])) {
$table->add('title', Q(rcube_label('filename')));
$table->add('header', Q($this->cal->attachment['name']));
$table->add('download-link', html::a('?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']), Q(rcube_label('download'))));
}
if (!empty($this->cal->attachment['size'])) {
$table->add('title', Q(rcube_label('filesize')));
$table->add('header', Q(show_bytes($this->cal->attachment['size'])));
}
return $table->show($attrib);
}
/**
* Handler for calendar form template.
* The form content could be overriden by the driver

View file

@ -19,10 +19,10 @@
<email>machniak@kolabsys.com</email>
<active>yes</active>
</developer>
<date>2011-11-01</date>
<date>2012-12-16</date>
<version>
<release>0.8</release>
<api>0.8</api>
<release>0.8-alpha</release>
<api>0.9-alpha</api>
</version>
<stability>
<release>stable</release>
@ -112,7 +112,6 @@
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="skins/classic/calendar.css" role="data"></file>
<file name="skins/classic/fullcalendar.css" role="data"></file>
<file name="skins/classic/fullcalendar.print.css" role="data"></file>
@ -178,7 +177,7 @@
<dependencies>
<required>
<php>
<min>5.2.1</min>
<min>5.3.1</min>
</php>
<pearinstaller>
<min>1.7.0</min>

View file

@ -18,6 +18,14 @@ body.calendarmain #mainscreen {
left: 0;
}
body.attachmentwin #mainscreen {
top: 60px;
}
body.attachmentwin #topnav .topright {
margin-top: 20px;
}
#calendarsidebar {
position: absolute;
top: 0;

View file

@ -4,19 +4,16 @@
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
<body class="extwin">
<body class="extwin attachmentwin">
<div id="header">
<div id="topline">
<div id="topnav">
<roundcube:object name="logo" src="/images/roundcube_logo.png" id="toplogo" border="0" alt="Logo" />
<div class="topright">
<a href="#close" class="closelink" onclick="self.close()"><roundcube:label name="close" /></a>
</div>
</div>
<div id="topnav">
<roundcube:object name="logo" src="/images/roundcube_logo.png" id="toplogo" border="0" alt="Logo" />
</div>
<br style="clear:both" />
</div>

View file

@ -5,8 +5,9 @@
*
* Provides utility functions for calendar-related modules such as
* - alarms display and dismissal
* - recurrence computation and UI elements
* - ical parsing and exporting
* - attachment handling
* - recurrence computation and UI elements (TODO)
* - ical parsing and exporting (TODO)
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
@ -456,6 +457,246 @@ class libcalendaring extends rcube_plugin
return html::tag('ul', $attrib + array('class' => 'toolbarmenu'), join("\n", $items), html::$common_attrib);
}
/********* Attachments handling *********/
/**
* Handler for attachment uploads
*/
public function attachment_upload($session_key, $id_prefix = '')
{
// Upload progress update
if (!empty($_GET['_progress'])) {
rcube_upload_progress();
}
$recid = $id_prefix . get_input_value('_id', RCUBE_INPUT_GPC);
$uploadid = get_input_value('_uploadid', RCUBE_INPUT_GPC);
if (!is_array($_SESSION[$session_key]) || $_SESSION[$session_key]['id'] != $recid) {
$_SESSION[$session_key] = array();
$_SESSION[$session_key]['id'] = $recid;
$_SESSION[$session_key]['attachments'] = array();
}
// clear all stored output properties (like scripts and env vars)
$this->rc->output->reset();
if (is_array($_FILES['_attachments']['tmp_name'])) {
foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
// Process uploaded attachment if there is no error
$err = $_FILES['_attachments']['error'][$i];
if (!$err) {
$attachment = array(
'path' => $filepath,
'size' => $_FILES['_attachments']['size'][$i],
'name' => $_FILES['_attachments']['name'][$i],
'mimetype' => rc_mime_content_type($filepath, $_FILES['_attachments']['name'][$i], $_FILES['_attachments']['type'][$i]),
'group' => $recid,
);
$attachment = $this->rc->plugins->exec_hook('attachment_upload', $attachment);
}
if (!$err && $attachment['status'] && !$attachment['abort']) {
$id = $attachment['id'];
// store new attachment in session
unset($attachment['status'], $attachment['abort']);
$_SESSION[$session_key]['attachments'][$id] = $attachment;
if (($icon = $_SESSION[$session_key . '_deleteicon']) && is_file($icon)) {
$button = html::img(array(
'src' => $icon,
'alt' => rcube_label('delete')
));
}
else {
$button = Q(rcube_label('delete'));
}
$content = html::a(array(
'href' => "#delete",
'class' => 'delete',
'onclick' => sprintf("return %s.remove_from_attachment_list('rcmfile%s')", JS_OBJECT_NAME, $id),
'title' => rcube_label('delete'),
), $button);
$content .= Q($attachment['name']);
$this->rc->output->command('add2attachment_list', "rcmfile$id", array(
'html' => $content,
'name' => $attachment['name'],
'mimetype' => $attachment['mimetype'],
'classname' => rcmail_filetype2classname($attachment['mimetype'], $attachment['name']),
'complete' => true), $uploadid);
}
else { // upload failed
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
$msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array(
'size' => show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
}
else if ($attachment['error']) {
$msg = $attachment['error'];
}
else {
$msg = rcube_label('fileuploaderror');
}
$this->rc->output->command('display_message', $msg, 'error');
$this->rc->output->command('remove_from_attachment_list', $uploadid);
}
}
}
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// if filesize exceeds post_max_size then $_FILES array is empty,
// show filesizeerror instead of fileuploaderror
if ($maxsize = ini_get('post_max_size'))
$msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array(
'size' => show_bytes(parse_bytes($maxsize)))));
else
$msg = rcube_label('fileuploaderror');
$this->rc->output->command('display_message', $msg, 'error');
$this->rc->output->command('remove_from_attachment_list', $uploadid);
}
$this->rc->output->send('iframe');
}
/**
* Deliver an event/task attachment to the client
* (similar as in Roundcube core program/steps/mail/get.inc)
*/
public function attachment_get($attachment)
{
ob_end_clean();
if ($attachment && $attachment['body']) {
// allow post-processing of the attachment body
$part = new rcube_message_part;
$part->filename = $attachment['name'];
$part->size = $attachment['size'];
$part->mimetype = $attachment['mimetype'];
$plugin = $this->rc->plugins->exec_hook('message_part_get', array(
'body' => $attachment['body'],
'mimetype' => strtolower($attachment['mimetype']),
'download' => !empty($_GET['_download']),
'part' => $part,
));
if ($plugin['abort'])
exit;
$mimetype = $plugin['mimetype'];
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
$browser = $this->rc->output->browser;
// send download headers
if ($plugin['download']) {
header("Content-Type: application/octet-stream");
if ($browser->ie)
header("Content-Type: application/force-download");
}
else if ($ctype_primary == 'text') {
header("Content-Type: text/$ctype_secondary");
}
else {
header("Content-Type: $mimetype");
header("Content-Transfer-Encoding: binary");
}
// display page, @TODO: support text/plain (and maybe some other text formats)
if ($mimetype == 'text/html' && empty($_GET['_download'])) {
$OUTPUT = new rcube_html_page();
// @TODO: use washtml on $body
$OUTPUT->write($plugin['body']);
}
else {
// don't kill the connection if download takes more than 30 sec.
@set_time_limit(0);
$filename = $attachment['name'];
$filename = preg_replace('[\r\n]', '', $filename);
if ($browser->ie && $browser->ver < 7)
$filename = rawurlencode(abbreviate_string($filename, 55));
else if ($browser->ie)
$filename = rawurlencode($filename);
else
$filename = addcslashes($filename, '"');
$disposition = !empty($_GET['_download']) ? 'attachment' : 'inline';
header("Content-Disposition: $disposition; filename=\"$filename\"");
echo $plugin['body'];
}
exit;
}
// if we arrive here, the requested part was not found
header('HTTP/1.1 404 Not Found');
exit;
}
/**
* Show "loading..." page in attachment iframe
*/
public function attachment_loading_page()
{
$url = str_replace('&_preload=1', '', $_SERVER['REQUEST_URI']);
$message = rcube_label('loadingdata');
header('Content-Type: text/html; charset=' . RCMAIL_CHARSET);
print "<html>\n<head>\n"
. '<meta http-equiv="refresh" content="0; url='.Q($url).'">' . "\n"
. '<meta http-equiv="content-type" content="text/html; charset='.RCMAIL_CHARSET.'">' . "\n"
. "</head>\n<body>\n$message\n</body>\n</html>";
exit;
}
/**
* Template object for attachment display frame
*/
public function attachment_frame($attrib = array())
{
$mimetype = strtolower($this->attachment['mimetype']);
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
$attrib['src'] = './?' . str_replace('_frame=', ($ctype_primary == 'text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']);
return html::iframe($attrib);
}
/**
*
*/
public function attachment_header($attrib = array())
{
$table = new html_table(array('cols' => 3));
if (!empty($this->attachment['name'])) {
$table->add('title', Q(rcube_label('filename')));
$table->add('header', Q($this->attachment['name']));
$table->add('download-link', html::a('?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']), Q(rcube_label('download'))));
}
if (!empty($this->attachment['size'])) {
$table->add('title', Q(rcube_label('filesize')));
$table->add('header', Q(show_bytes($this->attachment['size'])));
}
return $table->show($attrib);
}
/********* Static utility functions *********/
/**
* Convert the internal structured data into a vcalendar rrule 2.0 string
*/

View file

@ -17,6 +17,7 @@ $labels['title'] = 'Titel';
$labels['description'] = 'Beschreibung';
$labels['datetime'] = 'Datum/Zeit';
$labels['start'] = 'Beginn';
$labels['alarms'] = 'Erinnerung';
$labels['all'] = 'Alle';
$labels['flagged'] = 'Markiert';

View file

@ -17,6 +17,7 @@ $labels['title'] = 'Title';
$labels['description'] = 'Description';
$labels['datetime'] = 'Date/Time';
$labels['start'] = 'Start';
$labels['alarms'] = 'Reminder';
$labels['all'] = 'All';
$labels['flagged'] = 'Flagged';

View file

@ -29,6 +29,14 @@ div.uidialog {
display: none;
}
body.attachmentwin #mainscreen {
top: 60px;
}
body.attachmentwin #topnav .topright {
margin-top: 20px;
}
#sidebar {
position: absolute;
top: 0;

View file

@ -4,19 +4,16 @@
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
</head>
<body class="extwin">
<body class="extwin attachmentwin">
<div id="header">
<div id="topline">
<div id="topnav">
<roundcube:object name="logo" src="/images/roundcube_logo.png" id="toplogo" border="0" alt="Logo" />
<div class="topright">
<a href="#close" class="closelink" onclick="self.close()"><roundcube:label name="close" /></a>
</div>
</div>
<div id="topnav">
<roundcube:object name="logo" src="/images/roundcube_logo.png" id="toplogo" border="0" alt="Logo" />
</div>
<br style="clear:both" />
</div>

View file

@ -113,7 +113,7 @@
<span id="task-starttime"></span>
</div>
<div id="task-alarm" class="form-section">
<label><roundcube:label name="calendar.alarms" /></label>
<label><roundcube:label name="tasklist.alarms" /></label>
<span class="task-text"></span>
</div>
<div id="task-list" class="form-section">

View file

@ -32,7 +32,7 @@
<a href="#nodate" style="margin-left:1em" class="edit-nodate" rel="#taskedit-startdate,#taskedit-starttime"><roundcube:label name="tasklist.nodate" /></a>
</div>
<div class="form-section" id="taskedit-alarms">
<label for="taskedit-alarm"><roundcube:label name="calendar.alarms" /></label>
<label for="taskedit-alarm"><roundcube:label name="tasklist.alarms" /></label>
<roundcube:object name="plugin.alarm_select" />
</div>
<div class="form-section">

View file

@ -33,6 +33,8 @@ class tasklist extends rcube_plugin
const FILTER_MASK_FLAGGED = 64;
const FILTER_MASK_COMPLETE = 128;
const SESSION_KEY = 'tasklist_temp';
public static $filter_masks = array(
'today' => self::FILTER_MASK_TODAY,
'tomorrow' => self::FILTER_MASK_TOMORROW,
@ -308,9 +310,9 @@ class tasklist extends rcube_plugin
$attachments = array();
$taskid = $rec['id'];
if (is_array($_SESSION['tasklist_session']) && $_SESSION['tasklist_session']['id'] == $taskid) {
if (!empty($_SESSION['tasklist_session']['attachments'])) {
foreach ($_SESSION['tasklist_session']['attachments'] as $id => $attachment) {
if (is_array($_SESSION[self::SESSION_KEY]) && $_SESSION[self::SESSION_KEY]['id'] == $taskid) {
if (!empty($_SESSION[self::SESSION_KEY]['attachments'])) {
foreach ($_SESSION[self::SESSION_KEY]['attachments'] as $id => $attachment) {
if (is_array($rec['attachments']) && in_array($id, $rec['attachments'])) {
$attachments[$id] = $this->rc->plugins->exec_hook('attachment_get', $attachment);
unset($attachments[$id]['abort'], $attachments[$id]['group']);
@ -334,9 +336,9 @@ class tasklist extends rcube_plugin
private function cleanup_task(&$rec)
{
// remove temp. attachment files
if (!empty($_SESSION['tasklist_session']) && ($taskid = $_SESSION['tasklist_session']['id'])) {
if (!empty($_SESSION[self::SESSION_KEY]) && ($taskid = $_SESSION[self::SESSION_KEY]['id'])) {
$this->rc->plugins->exec_hook('attachments_cleanup', array('group' => $taskid));
$this->rc->session->remove('tasklist_session');
$this->rc->session->remove(self::SESSION_KEY);
}
}
@ -656,104 +658,13 @@ class tasklist extends rcube_plugin
/******* Attachment handling *******/
/*** pretty much the same as in plugins/calendar/calendar.php ***/
/**
* Handler for attachments upload
*/
public function attachment_upload()
{
// Upload progress update
if (!empty($_GET['_progress'])) {
rcube_upload_progress();
}
$taskid = get_input_value('_id', RCUBE_INPUT_GPC);
$uploadid = get_input_value('_uploadid', RCUBE_INPUT_GPC);
// prepare session storage
if (!is_array($_SESSION['tasklist_session']) || $_SESSION['tasklist_session']['id'] != $taskid) {
$_SESSION['tasklist_session'] = array();
$_SESSION['tasklist_session']['id'] = $taskid;
$_SESSION['tasklist_session']['attachments'] = array();
}
// clear all stored output properties (like scripts and env vars)
$this->rc->output->reset();
if (is_array($_FILES['_attachments']['tmp_name'])) {
foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
// Process uploaded attachment if there is no error
$err = $_FILES['_attachments']['error'][$i];
if (!$err) {
$attachment = array(
'path' => $filepath,
'size' => $_FILES['_attachments']['size'][$i],
'name' => $_FILES['_attachments']['name'][$i],
'mimetype' => rc_mime_content_type($filepath, $_FILES['_attachments']['name'][$i], $_FILES['_attachments']['type'][$i]),
'group' => $taskid,
);
$attachment = $this->rc->plugins->exec_hook('attachment_upload', $attachment);
}
if (!$err && $attachment['status'] && !$attachment['abort']) {
$id = $attachment['id'];
// store new attachment in session
unset($attachment['status'], $attachment['abort']);
$_SESSION['tasklist_session']['attachments'][$id] = $attachment;
$content = html::a(array(
'href' => "#delete",
'class' => 'delete',
'onclick' => sprintf("return %s.remove_from_attachment_list('rcmfile%s')", JS_OBJECT_NAME, $id),
'title' => rcube_label('delete'),
), Q(rcube_label('delete')));
$content .= Q($attachment['name']);
$this->rc->output->command('add2attachment_list', "rcmfile$id", array(
'html' => $content,
'name' => $attachment['name'],
'mimetype' => $attachment['mimetype'],
'classname' => rcmail_filetype2classname($attachment['mimetype'], $attachment['name']),
'complete' => true), $uploadid);
}
else { // upload failed
if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) {
$msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array(
'size' => show_bytes(parse_bytes(ini_get('upload_max_filesize'))))));
}
else if ($attachment['error']) {
$msg = $attachment['error'];
}
else {
$msg = rcube_label('fileuploaderror');
}
$this->rc->output->command('display_message', $msg, 'error');
$this->rc->output->command('remove_from_attachment_list', $uploadid);
}
}
}
else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// if filesize exceeds post_max_size then $_FILES array is empty,
// show filesizeerror instead of fileuploaderror
if ($maxsize = ini_get('post_max_size')) {
$msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array(
'size' => show_bytes(parse_bytes($maxsize)))));
}
else {
$msg = rcube_label('fileuploaderror');
}
$this->rc->output->command('display_message', $msg, 'error');
$this->rc->output->command('remove_from_attachment_list', $uploadid);
}
$this->rc->output->send('iframe');
$this->lib->attachment_upload(self::SESSION_KEY);
}
/**
@ -761,100 +672,29 @@ class tasklist extends rcube_plugin
*/
public function attachment_get()
{
// show loading page
if (!empty($_GET['_preload'])) {
return $this->lib->attachment_loading_page();
}
$task = get_input_value('_t', RCUBE_INPUT_GPC);
$list = get_input_value('_list', RCUBE_INPUT_GPC);
$id = get_input_value('_id', RCUBE_INPUT_GPC);
$task = array('id' => $task, 'list' => $list);
// show loading page
if (!empty($_GET['_preload'])) {
$url = str_replace('&_preload=1', '', $_SERVER['REQUEST_URI']);
$message = rcube_label('loadingdata');
header('Content-Type: text/html; charset=' . RCMAIL_CHARSET);
print "<html>\n<head>\n"
. '<meta http-equiv="refresh" content="0; url='.Q($url).'">' . "\n"
. '<meta http-equiv="content-type" content="text/html; charset='.RCMAIL_CHARSET.'">' . "\n"
. "</head>\n<body>\n$message\n</body>\n</html>";
exit;
}
ob_end_clean();
$attachment = $this->attachment = $this->driver->get_attachment($id, $task);
$attachment = $this->driver->get_attachment($id, $task);
// show part page
if (!empty($_GET['_frame'])) {
$this->register_handler('plugin.attachmentframe', array($this, 'attachment_frame'));
$this->register_handler('plugin.attachmentcontrols', array($this->ui, 'attachment_controls'));
$this->lib->attachment = $attachment;
$this->register_handler('plugin.attachmentframe', array($this->lib, 'attachment_frame'));
$this->register_handler('plugin.attachmentcontrols', array($this->lib, 'attachment_header'));
$this->rc->output->send('tasklist.attachment');
exit;
}
if ($attachment) {
// allow post-processing of the attachment body
$part = new rcube_message_part;
$part->filename = $attachment['name'];
$part->size = $attachment['size'];
$part->mimetype = $attachment['mimetype'];
$plugin = $this->rc->plugins->exec_hook('message_part_get', array(
'body' => $this->driver->get_attachment_body($id, $task),
'mimetype' => strtolower($attachment['mimetype']),
'download' => !empty($_GET['_download']),
'part' => $part,
));
if ($plugin['abort'])
exit;
$mimetype = $plugin['mimetype'];
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
$browser = $this->rc->output->browser;
// send download headers
if ($plugin['download']) {
header("Content-Type: application/octet-stream");
if ($browser->ie)
header("Content-Type: application/force-download");
}
else if ($ctype_primary == 'text') {
header("Content-Type: text/$ctype_secondary");
}
else {
header("Content-Type: $mimetype");
header("Content-Transfer-Encoding: binary");
}
// display page, @TODO: support text/plain (and maybe some other text formats)
if ($mimetype == 'text/html' && empty($_GET['_download'])) {
$OUTPUT = new rcube_html_page();
// @TODO: use washtml on $body
$OUTPUT->write($plugin['body']);
}
else {
// don't kill the connection if download takes more than 30 sec.
@set_time_limit(0);
$filename = $attachment['name'];
$filename = preg_replace('[\r\n]', '', $filename);
if ($browser->ie && $browser->ver < 7)
$filename = rawurlencode(abbreviate_string($filename, 55));
else if ($browser->ie)
$filename = rawurlencode($filename);
else
$filename = addcslashes($filename, '"');
$disposition = !empty($_GET['_download']) ? 'attachment' : 'inline';
header("Content-Disposition: $disposition; filename=\"$filename\"");
echo $plugin['body'];
}
exit;
// deliver attachment content
else if ($attachment) {
$attachment['body'] = $this->driver->get_attachment_body($id, $task);
$this->lib->attachment_get($attachment);
}
// if we arrive here, the requested part was not found
@ -862,21 +702,6 @@ class tasklist extends rcube_plugin
exit;
}
/**
* Template object for attachment display frame
*/
public function attachment_frame($attrib)
{
$attachment = $this->attachment;
$mimetype = strtolower($attachment['mimetype']);
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
$attrib['src'] = './?' . str_replace('_frame=', ($ctype_primary == 'text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']);
return html::iframe($attrib);
}
/******* Email related function *******/
@ -900,10 +725,10 @@ class tasklist extends rcube_plugin
// copy mail attachments to task
if ($message->attachments && $this->driver->attachments) {
if (!is_array($_SESSION['tasklist_session']) || $_SESSION['tasklist_session']['id'] != $task['id']) {
$_SESSION['tasklist_session'] = array();
$_SESSION['tasklist_session']['id'] = $task['id'];
$_SESSION['tasklist_session']['attachments'] = array();
if (!is_array($_SESSION[self::SESSION_KEY]) || $_SESSION[self::SESSION_KEY]['id'] != $task['id']) {
$_SESSION[self::SESSION_KEY] = array();
$_SESSION[self::SESSION_KEY]['id'] = $task['id'];
$_SESSION[self::SESSION_KEY]['attachments'] = array();
}
foreach ((array)$message->attachments as $part) {
@ -923,7 +748,7 @@ class tasklist extends rcube_plugin
// store new attachment in session
unset($attachment['status'], $attachment['abort'], $attachment['data']);
$_SESSION['tasklist_session']['attachments'][$id] = $attachment;
$_SESSION[self::SESSION_KEY]['attachments'][$id] = $attachment;
$attachment['id'] = 'rcmfile' . $attachment['id']; # add prefix to consider it 'new'
$task['attachments'][] = $attachment;

View file

@ -277,25 +277,4 @@ class tasklist_ui
}
}
/**
*
*/
function attachment_controls($attrib = array())
{
$table = new html_table(array('cols' => 3));
if (!empty($this->plugin->attachment['name'])) {
$table->add('title', Q(rcube_label('filename')));
$table->add('header', Q($this->plugin->attachment['name']));
$table->add('download-link', html::a('?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']), Q(rcube_label('download'))));
}
if (!empty($this->plugin->attachment['size'])) {
$table->add('title', Q(rcube_label('filesize')));
$table->add('header', Q(show_bytes($this->plugin->attachment['size'])));
}
return $table->show($attrib);
}
}