Finish attachment handling and display for events

This commit is contained in:
Thomas Bruederli 2012-04-25 19:26:40 +02:00
parent c9664e2bb7
commit 1b09ae2801
10 changed files with 117 additions and 85 deletions

View file

@ -1069,6 +1069,11 @@ class calendar extends rcube_plugin
$settings['identity'] = array('name' => $identity['name'], 'email' => $identity['email'], 'emails' => ';' . join(';', $identity['emails']));
}
// define list of file types which can be displayed inline
// same as in program/steps/mail/show.inc
$mimetypes = $this->rc->config->get('client_mimetypes', 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,application/x-javascript,application/pdf,application/x-shockwave-flash');
$settings['mimetypes'] = is_string($mimetypes) ? explode(',', $mimetypes) : (array)$mimetypes;
return $settings;
}
@ -1534,12 +1539,8 @@ class calendar extends rcube_plugin
}
ob_end_clean();
send_nocacheing_headers();
if (isset($_SESSION['calendar_attachment']))
$attachment = $_SESSION['calendar_attachment'];
else
$attachment = $_SESSION['calendar_attachment'] = $this->driver->get_attachment($id, $event);
$attachment = $GLOBALS['calendar_attachment'] = $this->driver->get_attachment($id, $event);
// show part page
if (!empty($_GET['_frame'])) {
@ -1550,12 +1551,16 @@ class calendar extends rcube_plugin
exit;
}
$this->rc->session->remove('calendar_attachment');
if ($attachment) {
$mimetype = strtolower($attachment['mimetype']);
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);
$body = $this->driver->get_attachment_body($id, $event);
// TODO: allow post-processing of the attachment body
//$plugin = $RCMAIL->plugins->exec_hook('message_part_get',
// array('uid' => $MESSAGE->uid, 'id' => $part->mime_id, 'mimetype' => $mimetype, 'part' => $part, 'download' => !empty($_GET['_download'])));
$browser = $this->rc->output->browser;
// send download headers
@ -1573,8 +1578,6 @@ class calendar extends rcube_plugin
header("Content-Transfer-Encoding: binary");
}
$body = $this->driver->get_attachment_body($id, $event);
// display page, @TODO: support text/plain (and maybe some other text formats)
if ($mimetype == 'text/html' && empty($_GET['_download'])) {
$OUTPUT = new rcube_html_page();
@ -1614,7 +1617,7 @@ class calendar extends rcube_plugin
*/
public function attachment_frame($attrib)
{
$attachment = $_SESSION['calendar_attachment'];
$attachment = $GLOBALS['calendar_attachment'];
$mimetype = strtolower($attachment['mimetype']);
list($ctype_primary, $ctype_secondary) = explode('/', $mimetype);

View file

@ -260,7 +260,7 @@ function rcube_calendar_ui(settings)
var qstring = '_id='+urlencode(att.id)+'&_event='+urlencode(event.recurrence_id||event.id)+'&_cal='+urlencode(event.calendar);
// open attachment in frame if it's of a supported mimetype
if (id && att.mimetype && $.inArray(att.mimetype, rcmail.mimetypes)>=0) {
if (id && att.mimetype && $.inArray(att.mimetype, settings.mimetypes)>=0) {
rcmail.attachment_win = window.open(rcmail.env.comm_path+'&_action=get-attachment&'+qstring+'&_frame=1', 'rcubeeventattachment');
if (rcmail.attachment_win) {
window.setTimeout(function() { rcmail.attachment_win.focus(); }, 10);
@ -268,6 +268,8 @@ function rcube_calendar_ui(settings)
}
}
return;
rcmail.goto_url('get-attachment', qstring+'&_download=1', false);
};

View file

@ -169,14 +169,6 @@ class kolab_calendar
return $this->storage;
}
/**
* Getter for the attachment body
*/
public function get_attachment_body($id)
{
return $this->storage->getAttachment($id);
}
/**
* Getter for a single event object
@ -427,15 +419,15 @@ class kolab_calendar
if ($record['end'] <= $record['start'] && $record['allday'])
$record['end'] = $record['start'] + 3600;
if (!empty($rec['_attachments'])) {
foreach ($rec['_attachments'] as $name => $attachment) {
// @TODO: 'type' and 'key' are the only supported (no 'size')
$attachments[] = array(
'id' => $attachment['key'],
'mimetype' => $attachment['type'],
'name' => $name,
);
if (!empty($record['_attachments'])) {
foreach ($record['_attachments'] as $name => $attachment) {
if ($attachment !== false) {
$attachment['name'] = $name;
$attachments[] = $attachment;
}
}
$record['attachments'] = $attachments;
}
$sensitivity_map = array_flip($this->sensitivity_map);
@ -461,28 +453,31 @@ class kolab_calendar
// in Horde attachments are indexed by name
$object['_attachments'] = array();
if (!empty($event['attachments'])) {
if (is_array($event['attachments'])) {
$collisions = array();
foreach ($event['attachments'] as $idx => $attachment) {
// Roundcube ID has nothing to do with Horde ID, remove it
if ($attachment['content'])
unset($attachment['id']);
// Horde code assumes that there will be no more than
// one file with the same name: make filenames unique
$filename = $attachment['name'];
if ($collisions[$filename]++) {
$ext = preg_match('/(\.[a-z0-9]{1,6})$/i', $filename, $m) ? $m[1] : null;
$attachment['name'] = basename($filename, $ext) . '-' . $collisions[$filename] . $ext;
// flagged for deletion => set to false
if ($attachment['_deleted']) {
$object['_attachments'][$attachment['name']] = false;
}
else {
// Horde code assumes that there will be no more than
// one file with the same name: make filenames unique
$filename = $attachment['name'];
if ($collisions[$filename]++) {
$ext = preg_match('/(\.[a-z0-9]{1,6})$/i', $filename, $m) ? $m[1] : null;
$attachment['name'] = basename($filename, $ext) . '-' . $collisions[$filename] . $ext;
}
// set type parameter
if ($attachment['mimetype'])
$attachment['type'] = $attachment['mimetype'];
$object['_attachments'][$attachment['name']] = $attachment;
unset($event['attachments'][$idx]);
$object['_attachments'][$attachment['name']] = $attachment;
}
}
unset($event['attachments']);
}
// translate sensitivity property

View file

@ -579,7 +579,7 @@ class kolab_driver extends calendar_driver
if (!empty($old['attachments'])) {
foreach ($old['attachments'] as $idx => $att) {
if ($att['id'] == $attachment) {
unset($old['attachments'][$idx]);
$old['attachments'][$idx]['_deleted'] = true;
}
}
}
@ -592,12 +592,12 @@ class kolab_driver extends calendar_driver
// skip entries without content (could be existing ones)
if (!$attachment['data'] && !$attachment['path'])
continue;
// we'll read file contacts into memory, Horde/Kolab classes does the same
// So we cannot save memory, rcube_imap class can do this better
$attachments[] = array(
'name' => $attachment['name'],
'type' => $attachment['mimetype'],
'content' => $attachment['data'] ? $attachment['data'] : file_get_contents($attachment['path']),
'mimetype' => $attachment['mimetype'],
'content' => $attachment['data'],
'path' => $attachment['path'],
);
}
}
@ -625,7 +625,7 @@ class kolab_driver extends calendar_driver
// copy attachment data to new event
foreach ((array)$event['attachments'] as $idx => $attachment) {
if (!$attachment['data'])
$attachment['data'] = $fromcalendar->get_attachment_body($attachment['id']);
$attachment['data'] = $fromcalendar->get_attachment_body($attachment['id'], $event);
}
$success = $storage->insert_event($event);
@ -875,13 +875,14 @@ class kolab_driver extends calendar_driver
/**
* Get attachment body
* @see calendar_driver::get_attachment_body()
*/
public function get_attachment_body($id, $event)
{
if (!($storage = $this->calendars[$event['calendar']]))
if (!($cal = $this->calendars[$event['calendar']]))
return false;
return $storage->get_attachment_body($id);
return $cal->storage->get_attachment($event['id'], $id);
}
/**

View file

@ -657,13 +657,13 @@ class calendar_ui
if (!empty($this->cal->attachment['name'])) {
$table->add('title', Q(rcube_label('filename')));
$table->add(null, Q($this->cal->attachment['name']));
$table->add(null, '[' . html::a('?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']), Q(rcube_label('download'))) . ']');
$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(null, Q(show_bytes($this->cal->attachment['size'])));
$table->add('header', Q(show_bytes($this->cal->attachment['size'])));
}
return $table->show($attrib);

View file

@ -286,39 +286,45 @@ a.miniColors-trigger {
#attachmentcontainer {
position: absolute;
top: 80px;
left: 20px;
right: 20px;
bottom: 20px;
top: 60px;
left: 0px;
right: 0px;
bottom: 0px;
}
#attachmentframe {
width: 100%;
height: 100%;
border: 1px solid #999999;
background-color: #F9F9F9;
border: 0;
background-color: #fff;
border-radius: 4px;
}
#partheader {
position: absolute;
top: 20px;
left: 220px;
right: 20px;
height: 40px;
position: relative;
padding: 3px 0;
background: #f9f9f9;
background: -moz-linear-gradient(top, #fff 0%, #e9e9e9 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fff), color-stop(100%,#e9e9e9));
background: -o-linear-gradient(top, #fff 0%, #e9e9e9 100%);
background: -ms-linear-gradient(top, #fff 0%, #e9e9e9 100%);
background: linear-gradient(top, #fff 0%, #e9e9e9 100%);
}
#partheader table td {
padding-left: 2px;
padding-right: 4px;
vertical-align: middle;
font-size: 11px;
color: #666;
padding: 2px 8px;
}
#partheader table td.title {
color: #666;
#partheader table td.header {
font-weight: bold;
}
#partheader table td.title a {
color: #666;
text-decoration: none;
}
#edit-attachments {
margin-top: 0.6em;
}

View file

@ -26,7 +26,7 @@
</div>
<div id="attachmentcontainer" class="uibox">
<roundcube:object name="plugin.attachmentframe" id="attachmentframe" style="width:100%; height:100%" />
<roundcube:object name="plugin.attachmentframe" id="attachmentframe" class="header-table" style="width:100%" />
</div>
</div>

View file

@ -1057,7 +1057,7 @@ class rcube_kolab_contacts extends rcube_addressbook
if ($record['photo'] && strlen($record['photo']) < 255 && ($att = $record['_attachments'][$record['photo']])) {
// only fetch photo content if requested
if ($this->action == 'photo')
$record['photo'] = $att['content'] ? $att['content'] : $this->storagefolder->get_attachment($record['uid'], $att['key']);
$record['photo'] = $att['content'] ? $att['content'] : $this->storagefolder->get_attachment($record['uid'], $att['id']);
}
// truncate publickey value for display
@ -1123,7 +1123,7 @@ class rcube_kolab_contacts extends rcube_addressbook
if ($contact['photo']) {
$attkey = 'photo.attachment';
$contact['_attachments'][$attkey] = array(
'type' => rc_image_content_type($contact['photo']),
'mimetype' => rc_image_content_type($contact['photo']),
'content' => preg_match('![^a-z0-9/=+-]!i', $contact['photo']) ? $contact['photo'] : base64_decode($contact['photo']),
);
$contact['photo'] = $attkey;

View file

@ -280,7 +280,17 @@ class kolab_format_event extends kolab_format
}
$this->obj->setAlarms($valarms);
// TODO: save attachments
// save attachments
$vattach = new vectorattachment;
foreach ((array)$object['_attachments'] as $name => $attr) {
if (empty($attr))
continue;
$attach = new Attachment;
$attach->setLabel($name);
$attach->setUri('cid:' . $name, $attr['mimetype']);
$vattach->push($attach);
}
$this->obj->setAttachments($vattach);
// cache this data
unset($object['_formatobj']);
@ -425,7 +435,22 @@ class kolab_format_event extends kolab_format
}
}
// TODO: handle attachments
// handle attachments
$vattach = $this->obj->attachments();
for ($i=0; $i < $vattach->size(); $i++) {
$attach = $vattach->get($i);
// skip cid: attachments which are mime message parts handled by kolab_storage_folder
if (substr($attach->uri(), 0, 4) != 'cid') {
$name = $attach->label();
$data = $attach->data();
$object['_attachments'][$name] = array(
'mimetype' => $attach->mimetype(),
'size' => strlen($data),
'content' => $data,
);
}
}
$this->data = $object;
return $this->data;

View file

@ -350,8 +350,8 @@ class kolab_storage_folder
}
else if ($part->filename) {
$attachments[$part->filename] = array(
'key' => $part->mime_id,
'type' => $part->mimetype,
'id' => $part->mime_id,
'mimetype' => $part->mimetype,
'size' => $part->size,
);
}
@ -388,13 +388,10 @@ class kolab_storage_folder
}
if ($format->is_valid()) {
if ($formatobj)
return $format;
$object = $format->to_array();
$object['_msguid'] = $msguid;
$object['_mailbox'] = $this->name;
$object['_attachments'] = $attachments;
$object['_attachments'] = array_merge((array)$object['_attachments'], $attachments);
$object['_formatobj'] = $format;
$this->objcache[$msguid] = $object;
@ -425,8 +422,8 @@ class kolab_storage_folder
$object['_attachments'][$name] = $old['_attachments'][$name];
}
// load photo.attachment from old Kolab2 format to be directly embedded in xcard block
if ($name == 'photo.attachment' && !isset($object['photo']) && !$object['_attachments'][$name]['content'] && $att['key']) {
$object['photo'] = $this->get_attachment($object['_msguid'], $att['key'], $object['_mailbox']);
if ($name == 'photo.attachment' && !isset($object['photo']) && !$object['_attachments'][$name]['content'] && $att['id']) {
$object['photo'] = $this->get_attachment($object['_msguid'], $att['id'], $object['_mailbox']);
unset($object['_attachments'][$name]);
}
}
@ -601,12 +598,15 @@ class kolab_storage_folder
// save object attachments as separate parts
// TODO: optimize memory consumption by using tempfiles for transfer
foreach ((array)$object['_attachments'] as $name => $att) {
if (empty($att['content']) && !empty($att['key'])) {
if (empty($att['content']) && !empty($att['id'])) {
$msguid = !empty($object['_msguid']) ? $object['_msguid'] : $object['uid'];
$att['content'] = $this->get_attachment($msguid, $att['key'], $object['_mailbox']);
$att['content'] = $this->get_attachment($msguid, $att['id'], $object['_mailbox']);
}
if (!empty($att['content'])) {
$mime->addAttachment($att['content'], $att['type'], $name, false);
$mime->addAttachment($att['content'], $att['mimetype'], $name, false);
}
else if (!empty($att['path'])) {
$mime->addAttachment($att['path'], $att['mimetype'], $name, true);
}
}
@ -681,7 +681,7 @@ class kolab_storage_folder
*/
public function getOwner()
{
console("Call to deprecated method kolab_storage_folder::getOwner()");
PEAR::raiseError("Call to deprecated method kolab_storage_folder::getOwner()");
return $this->get_owner();
}