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'])); $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; return $settings;
} }
@ -1534,12 +1539,8 @@ class calendar extends rcube_plugin
} }
ob_end_clean(); ob_end_clean();
send_nocacheing_headers();
if (isset($_SESSION['calendar_attachment'])) $attachment = $GLOBALS['calendar_attachment'] = $this->driver->get_attachment($id, $event);
$attachment = $_SESSION['calendar_attachment'];
else
$attachment = $_SESSION['calendar_attachment'] = $this->driver->get_attachment($id, $event);
// show part page // show part page
if (!empty($_GET['_frame'])) { if (!empty($_GET['_frame'])) {
@ -1550,12 +1551,16 @@ class calendar extends rcube_plugin
exit; exit;
} }
$this->rc->session->remove('calendar_attachment');
if ($attachment) { if ($attachment) {
$mimetype = strtolower($attachment['mimetype']); $mimetype = strtolower($attachment['mimetype']);
list($ctype_primary, $ctype_secondary) = explode('/', $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; $browser = $this->rc->output->browser;
// send download headers // send download headers
@ -1573,8 +1578,6 @@ class calendar extends rcube_plugin
header("Content-Transfer-Encoding: binary"); 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) // display page, @TODO: support text/plain (and maybe some other text formats)
if ($mimetype == 'text/html' && empty($_GET['_download'])) { if ($mimetype == 'text/html' && empty($_GET['_download'])) {
$OUTPUT = new rcube_html_page(); $OUTPUT = new rcube_html_page();
@ -1614,7 +1617,7 @@ class calendar extends rcube_plugin
*/ */
public function attachment_frame($attrib) public function attachment_frame($attrib)
{ {
$attachment = $_SESSION['calendar_attachment']; $attachment = $GLOBALS['calendar_attachment'];
$mimetype = strtolower($attachment['mimetype']); $mimetype = strtolower($attachment['mimetype']);
list($ctype_primary, $ctype_secondary) = explode('/', $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); 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 // 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'); rcmail.attachment_win = window.open(rcmail.env.comm_path+'&_action=get-attachment&'+qstring+'&_frame=1', 'rcubeeventattachment');
if (rcmail.attachment_win) { if (rcmail.attachment_win) {
window.setTimeout(function() { rcmail.attachment_win.focus(); }, 10); 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); rcmail.goto_url('get-attachment', qstring+'&_download=1', false);
}; };

View file

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

View file

@ -579,7 +579,7 @@ class kolab_driver extends calendar_driver
if (!empty($old['attachments'])) { if (!empty($old['attachments'])) {
foreach ($old['attachments'] as $idx => $att) { foreach ($old['attachments'] as $idx => $att) {
if ($att['id'] == $attachment) { 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) // skip entries without content (could be existing ones)
if (!$attachment['data'] && !$attachment['path']) if (!$attachment['data'] && !$attachment['path'])
continue; 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( $attachments[] = array(
'name' => $attachment['name'], 'name' => $attachment['name'],
'type' => $attachment['mimetype'], 'mimetype' => $attachment['mimetype'],
'content' => $attachment['data'] ? $attachment['data'] : file_get_contents($attachment['path']), 'content' => $attachment['data'],
'path' => $attachment['path'],
); );
} }
} }
@ -625,7 +625,7 @@ class kolab_driver extends calendar_driver
// copy attachment data to new event // copy attachment data to new event
foreach ((array)$event['attachments'] as $idx => $attachment) { foreach ((array)$event['attachments'] as $idx => $attachment) {
if (!$attachment['data']) 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); $success = $storage->insert_event($event);
@ -875,13 +875,14 @@ class kolab_driver extends calendar_driver
/** /**
* Get attachment body * Get attachment body
* @see calendar_driver::get_attachment_body()
*/ */
public function get_attachment_body($id, $event) public function get_attachment_body($id, $event)
{ {
if (!($storage = $this->calendars[$event['calendar']])) if (!($cal = $this->calendars[$event['calendar']]))
return false; 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'])) { if (!empty($this->cal->attachment['name'])) {
$table->add('title', Q(rcube_label('filename'))); $table->add('title', Q(rcube_label('filename')));
$table->add(null, Q($this->cal->attachment['name'])); $table->add('header', Q($this->cal->attachment['name']));
$table->add(null, '[' . html::a('?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']), Q(rcube_label('download'))) . ']'); $table->add('download-link', html::a('?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']), Q(rcube_label('download'))));
} }
if (!empty($this->cal->attachment['size'])) { if (!empty($this->cal->attachment['size'])) {
$table->add('title', Q(rcube_label('filesize'))); $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); return $table->show($attrib);

View file

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

View file

@ -26,7 +26,7 @@
</div> </div>
<div id="attachmentcontainer" class="uibox"> <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>
</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']])) { if ($record['photo'] && strlen($record['photo']) < 255 && ($att = $record['_attachments'][$record['photo']])) {
// only fetch photo content if requested // only fetch photo content if requested
if ($this->action == 'photo') 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 // truncate publickey value for display
@ -1123,7 +1123,7 @@ class rcube_kolab_contacts extends rcube_addressbook
if ($contact['photo']) { if ($contact['photo']) {
$attkey = 'photo.attachment'; $attkey = 'photo.attachment';
$contact['_attachments'][$attkey] = array( $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']), 'content' => preg_match('![^a-z0-9/=+-]!i', $contact['photo']) ? $contact['photo'] : base64_decode($contact['photo']),
); );
$contact['photo'] = $attkey; $contact['photo'] = $attkey;

View file

@ -280,7 +280,17 @@ class kolab_format_event extends kolab_format
} }
$this->obj->setAlarms($valarms); $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 // cache this data
unset($object['_formatobj']); 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; $this->data = $object;
return $this->data; return $this->data;

View file

@ -350,8 +350,8 @@ class kolab_storage_folder
} }
else if ($part->filename) { else if ($part->filename) {
$attachments[$part->filename] = array( $attachments[$part->filename] = array(
'key' => $part->mime_id, 'id' => $part->mime_id,
'type' => $part->mimetype, 'mimetype' => $part->mimetype,
'size' => $part->size, 'size' => $part->size,
); );
} }
@ -388,13 +388,10 @@ class kolab_storage_folder
} }
if ($format->is_valid()) { if ($format->is_valid()) {
if ($formatobj)
return $format;
$object = $format->to_array(); $object = $format->to_array();
$object['_msguid'] = $msguid; $object['_msguid'] = $msguid;
$object['_mailbox'] = $this->name; $object['_mailbox'] = $this->name;
$object['_attachments'] = $attachments; $object['_attachments'] = array_merge((array)$object['_attachments'], $attachments);
$object['_formatobj'] = $format; $object['_formatobj'] = $format;
$this->objcache[$msguid] = $object; $this->objcache[$msguid] = $object;
@ -425,8 +422,8 @@ class kolab_storage_folder
$object['_attachments'][$name] = $old['_attachments'][$name]; $object['_attachments'][$name] = $old['_attachments'][$name];
} }
// load photo.attachment from old Kolab2 format to be directly embedded in xcard block // 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']) { if ($name == 'photo.attachment' && !isset($object['photo']) && !$object['_attachments'][$name]['content'] && $att['id']) {
$object['photo'] = $this->get_attachment($object['_msguid'], $att['key'], $object['_mailbox']); $object['photo'] = $this->get_attachment($object['_msguid'], $att['id'], $object['_mailbox']);
unset($object['_attachments'][$name]); unset($object['_attachments'][$name]);
} }
} }
@ -601,12 +598,15 @@ class kolab_storage_folder
// save object attachments as separate parts // save object attachments as separate parts
// TODO: optimize memory consumption by using tempfiles for transfer // TODO: optimize memory consumption by using tempfiles for transfer
foreach ((array)$object['_attachments'] as $name => $att) { 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']; $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'])) { 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() 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(); return $this->get_owner();
} }