[Svn] r2356 - in branches/devel-api: plugins/database_attachments plugins/filesystem_attachments program/steps/mail
trac at roundcube.net
trac at roundcube.net
Tue Mar 17 16:04:05 CET 2009
Author: thomasb
Date: 2009-03-17 10:04:05 -0500 (Tue, 17 Mar 2009)
New Revision: 2356
Modified:
branches/devel-api/plugins/database_attachments/database_attachments.php
branches/devel-api/plugins/filesystem_attachments/filesystem_attachments.php
branches/devel-api/program/steps/mail/attachments.inc
branches/devel-api/program/steps/mail/compose.inc
branches/devel-api/program/steps/mail/sendmail.inc
Log:
Refactoring of the attachments core plugins:
- let the application manage the compose-attachments array
- unify input and output parameters
- get rid of local temp files, directly pass file contents
- codestyle improvements
Modified: branches/devel-api/plugins/database_attachments/database_attachments.php
===================================================================
--- branches/devel-api/plugins/database_attachments/database_attachments.php 2009-03-17 14:36:00 UTC (rev 2355)
+++ branches/devel-api/plugins/database_attachments/database_attachments.php 2009-03-17 15:04:05 UTC (rev 2356)
@@ -19,98 +19,109 @@
// A prefix for the cache key used in the session and in the key field of the cache table
private $cache_prefix = "db_attach";
-
- function _key($filepath){
+ /**
+ * Helper method to generate a unique key for the given attachment file
+ */
+ private function _key($filepath)
+ {
return $this->cache_prefix.md5(mktime().$filepath.$_SESSION['user_id']);
}
- // Save a newly uploaded attachment
- function upload($args){
- $args['status'] = TRUE;
+ /**
+ * Save a newly uploaded attachment
+ */
+ function upload($args)
+ {
+ $args['status'] = false;
$rcmail = rcmail::get_instance();
- $key = $this->_key($args['filepath']);
- $data = base64_encode(file_get_contents($args['filepath']));
+ $key = $this->_key($args['path']);
+ $data = base64_encode(file_get_contents($args['path']));
$status = $rcmail->db->query(
"INSERT INTO ".get_table_name('cache')."
- (created, user_id, cache_key, data)
- VALUES (".$rcmail->db->now().", ?, ?, ?)",
+ (created, user_id, cache_key, data)
+ VALUES (".$rcmail->db->now().", ?, ?, ?)",
$_SESSION['user_id'],
$key,
- $data);
- if($status){
+ $data);
+
+ if ($status) {
$args['id'] = $key;
- $_SESSION['compose']['attachments'][$key] = array(
- 'name' => $_FILES['_attachments']['name'][$args['index']],
- 'mimetype' => rc_mime_content_type($args['filepath'], $_FILES['_attachments']['type'][0]),
- 'path' => "stored in database",
- );
- } else {
- $args['status'] = FALSE;
+ $args['status'] = true;
+ unset($args['path']);
}
+
return $args;
}
- // Save an attachment from a non-upload source (draft or forward)
- function save($args){
- $args['status'] = TRUE;
+ /**
+ * Save an attachment from a non-upload source (draft or forward)
+ */
+ function save($args)
+ {
+ $args['status'] = false;
$rcmail = rcmail::get_instance();
- $key = $this->_key($args['filename']);
- $data = base64_encode($args['attachment']);
+ $key = $this->_key($args['name']);
+ $data = base64_encode($args['data']);
$status = $rcmail->db->query(
"INSERT INTO ".get_table_name('cache')."
- (created, user_id, cache_key, data)
- VALUES (".$rcmail->db->now().", ?, ?, ?)",
+ (created, user_id, cache_key, data)
+ VALUES (".$rcmail->db->now().", ?, ?, ?)",
$_SESSION['user_id'],
$key,
- $data);
- $args['id'] = $key;
- if (!$status)
- {
- $args['status'] = FALSE;
+ $data);
+
+ if ($status) {
+ $args['id'] = $key;
+ $args['status'] = true;
}
return $args;
}
- // Remove an attachment from storage
- // This is triggered by the remove attachment button on the compose screen
- function remove($args){
- $args['status'] = TRUE;
+ /**
+ * Remove an attachment from storage
+ * This is triggered by the remove attachment button on the compose screen
+ */
+ function remove($args)
+ {
+ $args['status'] = false;
$rcmail = rcmail::get_instance();
$status = $rcmail->db->query(
"DELETE FROM ".get_table_name('cache')."
- WHERE user_id=?
- AND cache_key=?",
+ WHERE user_id=?
+ AND cache_key=?",
$_SESSION['user_id'],
$args['id']);
- if(!$status){
- $args['status'] = false;
+ if ($status) {
+ $args['status'] = true;
}
+
return $args;
}
- // When composing an html message, image attachments may be shown
- // For this plugin, $this->get_attachment will check the file and
- // place it on disk
- function display($args){
+ /**
+ * When composing an html message, image attachments may be shown
+ * For this plugin, $this->get_attachment will check the file and
+ * return it's contents
+ */
+ function display($args)
+ {
return $this->get_attachment($args);
}
- // When displaying or sending the attachment the file must be temporarily
- // copied to disk. This function is also called by the display_attachment hook.
- function get_attachment($args){
- $args['status'] = TRUE;
- $args['erase_after_send'] = TRUE;
+ /**
+ * When displaying or sending the attachment the file contents are fetched
+ * using this method. This is also called by the display_attachment hook.
+ */
+ function get_attachment($args)
+ {
$rcmail = rcmail::get_instance();
- if (!is_array($_SESSION['compose']['attachments'][$args['id']])){
- $args['status'] = FALSE;
- }
- else{
- $sql_result = $rcmail->db->query(
+
+ $sql_result = $rcmail->db->query(
"SELECT cache_id, data
FROM ".get_table_name('cache')."
WHERE user_id=?
@@ -118,42 +129,24 @@
$_SESSION['user_id'],
$args['id']);
- if ($sql_arr = $rcmail->db->fetch_assoc($sql_result)) {
- $cache_data = base64_decode($sql_arr['data']);
- $temp_dir = unslashify($rcmail->config->get('temp_dir'));
- $tmp_path = tempnam($temp_dir, 'rcmAttmnt');
- file_put_contents($tmp_path, $cache_data);
- $_SESSION['compose']['attachments'][$args['id']]['path'] = $tmp_path;
- $_SESSION['plugins']['database_attachments']['tmp_files'][] = $tmp_path;
- $args['attachment']['path'] = $tmp_path;
- } else {
- $args['status'] = FALSE;
- }
-
+ if ($sql_arr = $rcmail->db->fetch_assoc($sql_result)) {
+ $args['data'] = base64_decode($sql_arr['data']);
+ $args['status'] = true;
}
+
return $args;
}
- // Delete all temp files associated with this user
- function cleanup($args){
+
+ /**
+ * Delete all temp files associated with this user
+ */
+ function cleanup($args)
+ {
$rcmail = rcmail::get_instance();
$rcmail->db->query(
"DELETE FROM ".get_table_name('cache')."
- WHERE user_id=?
- AND cache_key like '{$this->cache_prefix}%'",
- $_SESSION['user_id']);
-
- // When sending, attachments are copied to disk and should now be cleaned up
- // Note that the cleanup must happen during the same php script execution
- // as the send so that we can be sure it's the same machine in load ballanced
- // environments.
- if (is_array($_SESSION['plugins']['database_attachments']['tmp_files'])){
- foreach ($_SESSION['plugins']['database_attachments']['tmp_files'] as $i=>$filename){
- if(file_exists($filename)){
- unlink($filename);
- }
- unset($_SESSION['plugins']['database_attachments']['tmp_files']);
- }
- }
- return $args;
+ WHERE user_id=?
+ AND cache_key like '{$this->cache_prefix}%'",
+ $_SESSION['user_id']);
}
}
Modified: branches/devel-api/plugins/filesystem_attachments/filesystem_attachments.php
===================================================================
--- branches/devel-api/plugins/filesystem_attachments/filesystem_attachments.php 2009-03-17 14:36:00 UTC (rev 2355)
+++ branches/devel-api/plugins/filesystem_attachments/filesystem_attachments.php 2009-03-17 15:04:05 UTC (rev 2356)
@@ -10,17 +10,17 @@
*
* Developers may wish to extend this class when creating attachment
* handler plugins:
+ * require_once('plugins/filesystem_attachments/filesystem_attachments.php');
+ * class myCustom_attachments extends filesystem_attachments
*
- * require_once('plugins/filesystem_attachments/filesystem_attachments.php');
- * class myCustom_attachments extends filesystem_attachments
- *
* @author Ziba Scott <ziba at umich.edu>
* @author Thomas Bruederli <roundcube at gmail.com>
*
*/
class filesystem_attachments extends rcube_plugin
{
-
+ public $task = 'mail';
+
function init()
{
// Save a newly uploaded attachment
@@ -42,91 +42,91 @@
$this->add_hook('cleanup_attachments', array($this, 'cleanup'));
}
- // Save a newly uploaded attachment
- function upload($args){
- $args['status'] = TRUE;
+ /**
+ * Save a newly uploaded attachment
+ */
+ function upload($args)
+ {
+ $args['status'] = false;
$rcmail = rcmail::get_instance();
+
// use common temp dir for file uploads
$temp_dir = unslashify($rcmail->config->get('temp_dir'));
$tmpfname = tempnam($temp_dir, 'rcmAttmnt');
- $_SESSION['plugins']['filesystem_attachments']['tmp_files'][] = $tmpfname;
- if (move_uploaded_file($args['filepath'], $tmpfname)) {
- $id = count($_SESSION['compose']['attachments']);
- $args['id'] = $id;
+
+ if (move_uploaded_file($args['path'], $tmpfname)) {
+ $args['id'] = count($_SESSION['plugins']['filesystem_attachments']['tmp_files'])+1;
+ $args['path'] = $tmpfname;
+ $args['status'] = true;
- $_SESSION['compose']['attachments'][] = array(
- 'name' => $_FILES['_attachments']['name'][$args['index']],
- 'mimetype' => rc_mime_content_type($tmpfname, $_FILES['_attachments']['type'][0]),
- 'path' => $tmpfname,
- );
-
// Note the file for later cleanup
$_SESSION['plugins']['filesystem_attachments']['tmp_files'][] = $tmpfname;
}
- else{
- $args['status'] = FALSE;
- }
+
return $args;
}
- // Save an attachment from a non-upload source (draft or forward)
- function save($args){
- $args['status'] = TRUE;
+ /**
+ * Save an attachment from a non-upload source (draft or forward)
+ */
+ function save($args)
+ {
+ $args['status'] = false;
$rcmail = rcmail::get_instance();
$temp_dir = unslashify($rcmail->config->get('temp_dir'));
$tmp_path = tempnam($temp_dir, 'rcmAttmnt');
- // Note the file for later cleanup
- $_SESSION['plugins']['filesystem_attachments']['tmp_files'][] = $tmp_path;
-
- if ($fp = fopen($tmp_path, 'w'))
- {
- fwrite($fp, $args['attachment']);
+ if ($fp = fopen($tmp_path, 'w')) {
+ fwrite($fp, $args['data']);
fclose($fp);
+
+ $args['id'] = count($_SESSION['plugins']['filesystem_attachments']['tmp_files'])+1;
+ $args['path'] = $tmp_path;
+ $args['status'] = true;
+
+ // Note the file for later cleanup
+ $_SESSION['plugins']['filesystem_attachments']['tmp_files'][] = $tmp_path;
}
- else{
- $args['status'] = FALSE;
- }
- $args['tmp_path'] = $tmp_path;
- $args['id'] = count($_SESSION['compose']['attachments']);
-
return $args;
}
- // Remove an attachment from storage
- // This is triggered by the remove attachment button on the compose screen
- function remove($args){
- $args['status'] = TRUE;
- $id = $args['id'];
- if (is_array($_SESSION['compose']['attachments'][$id]))
- {
- @unlink($_SESSION['compose']['attachments'][$id]['path']);
- } else {
- $args['status'] = TRUE;
- }
+ /**
+ * Remove an attachment from storage
+ * This is triggered by the remove attachment button on the compose screen
+ */
+ function remove($args)
+ {
+ $args['status'] = @unlink($args['path']);
return $args;
}
- // When composing an html message, image attachments may be shown
- // For this plugin, the file is already in place, just check for
- // the existance of the proper metadata
- function display($args){
- $args['status'] = TRUE;
- if (!is_array($_SESSION['compose']['attachments'][$args['id']])){
- $args['status'] = FALSE;
- }
+ /**
+ * When composing an html message, image attachments may be shown
+ * For this plugin, the file is already in place, just check for
+ * the existance of the proper metadata
+ */
+ function display($args)
+ {
+ $args['status'] = file_exists($args['path']);
return $args;
}
- // This attachment plugin doesn't require any steps to put the file
- // on disk for use. This stub function is kept here to make this
- // class handy as a parent class for other plugins which may need it.
- function get_attachment($args){
+ /**
+ * This attachment plugin doesn't require any steps to put the file
+ * on disk for use. This stub function is kept here to make this
+ * class handy as a parent class for other plugins which may need it.
+ */
+ function get_attachment($args)
+ {
return $args;
}
- // Delete all temp files associated with this user
- function cleanup($args){
+
+ /**
+ * Delete all temp files associated with this user
+ */
+ function cleanup($args)
+ {
// $_SESSION['compose']['attachments'] is not a complete record of
// temporary files because loading a draft or starting a forward copies
// the file to disk, but does not make an entry in that array
Modified: branches/devel-api/program/steps/mail/attachments.inc
===================================================================
--- branches/devel-api/program/steps/mail/attachments.inc 2009-03-17 14:36:00 UTC (rev 2355)
+++ branches/devel-api/program/steps/mail/attachments.inc 2009-03-17 15:04:05 UTC (rev 2356)
@@ -28,34 +28,39 @@
// remove an attachment
if ($RCMAIL->action=='remove-attachment')
{
- $plugin = rcmail::get_instance()->plugins->exec_hook('remove_attachment',array('id'=>substr($_POST['_file'],7)));
- if ($plugin['status'])
- {
- $id = $plugin['id'];
- if (is_array($_SESSION['compose']['attachments'][$id]))
- {
+ $id = 'undefined';
+ if (preg_match('/^rcmfile(\w+)$/', $_POST['_file'], $regs))
+ $id = $regs[1];
+ if ($attachment = $_SESSION['compose']['attachments'][$id])
+ $attachment = $RCMAIL->plugins->exec_hook('remove_attachment', $attachment);
+ if ($attachment['status']) {
+ if (is_array($_SESSION['compose']['attachments'][$id])) {
unset($_SESSION['compose']['attachments'][$id]);
$OUTPUT->command('remove_from_attachment_list', "rcmfile$id");
- $OUTPUT->send();
}
}
+
+ $OUTPUT->send();
exit;
}
if ($RCMAIL->action=='display-attachment')
{
- $plugin = rcmail::get_instance()->plugins->exec_hook('display_attachment',array('id'=>substr($_GET['_file'],7)));
- if ($plugin['status'])
- {
- $id = $plugin['id'];
- $apath = $_SESSION['compose']['attachments'][$id]['path'];
- header('Content-Type: ' . $_SESSION['compose']['attachments'][$id]['mimetype']);
- header('Content-Length: ' . filesize($apath));
- readfile($apath);
- // plugins that don't use disk storage will want this temp file removed after use
- if($plugin['erase_after_send']){
- unlink($apath);
- }
+ $id = 'undefined';
+ if (preg_match('/^rcmfile(\w+)$/', $_GET['_file'], $regs))
+ $id = $regs[1];
+ if ($attachment = $_SESSION['compose']['attachments'][$id])
+ $attachment = $RCMAIL->plugins->exec_hook('display_attachment', $attachment);
+
+ if ($attachment['status']) {
+ $size = $attachment['data'] ? strlen($attachment['data']) : @filesize($attachment['path']);
+ header('Content-Type: ' . $attachment['mimetype']);
+ header('Content-Length: ' . $size);
+
+ if ($attachment['data'])
+ echo $attachment['data'];
+ else if ($attachment['path'])
+ readfile($attachment['path']);
}
exit;
}
@@ -74,9 +79,21 @@
if (is_array($_FILES['_attachments']['tmp_name'])) {
foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
- $plugin = rcmail::get_instance()->plugins->exec_hook('upload_attachment',array('filepath'=>$filepath,'index'=>$i));
- if ($plugin['status']) {
- $id = $plugin['id'];
+
+ $attachment = array(
+ 'path' => $filepath,
+ 'name' => $_FILES['_attachments']['name'][$i],
+ 'mimetype' => rc_mime_content_type($tmpfname, $_FILES['_attachments']['type'][$i])
+ );
+
+ $attachment = $RCMAIL->plugins->exec_hook('upload_attachment', $attachment);
+ if ($attachment['status']) {
+ $id = $attachment['id'];
+
+ // store new attachment in session
+ unset($attachment['status']);
+ $_SESSION['compose']['attachments'][$id] = $attachment;
+
if (is_file($icon = $CONFIG['skin_path'] . '/images/icons/remove-attachment.png')) {
$button = html::img(array(
'src' => $icon,
@@ -93,9 +110,9 @@
'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", JS_OBJECT_NAME, $id),
'title' => rcube_label('delete'),
), $button);
+
+ $content .= Q($attachment['name']);
- $content .= Q($_FILES['_attachments']['name'][$i]);
-
$OUTPUT->command('add2attachment_list', "rcmfile$id", $content);
}
else { // upload failed
Modified: branches/devel-api/program/steps/mail/compose.inc
===================================================================
--- branches/devel-api/program/steps/mail/compose.inc 2009-03-17 14:36:00 UTC (rev 2355)
+++ branches/devel-api/program/steps/mail/compose.inc 2009-03-17 15:04:05 UTC (rev 2356)
@@ -612,24 +612,22 @@
function rcmail_save_attachment(&$message, $pid)
{
- global $RCMAIL;
-
$part = $message->mime_parts[$pid];
- $attachment = $message->get_part_content($pid);
- $plugin = rcmail::get_instance()->plugins->exec_hook('save_attachment',array('attachment'=>$attachment,'filename'=>$part->filename));
- if ($plugin['status'])
- {
- return array(
- 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary,
- 'name' => $part->filename,
- 'path' => $plugin['tmp_path'],
- 'content_id' => $part->content_id,
- 'id' => $plugin['id']
- );
- } else {
- return FALSE;
+ $attachment = array(
+ 'name' => $part->filename,
+ 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary,
+ 'content_id' => $part->content_id,
+ 'data' => $message->get_part_content($pid),
+ );
+
+ $attachment = rcmail::get_instance()->plugins->exec_hook('save_attachment', $attachment);
+ if ($attachment['status']) {
+ unset($attachment['data'], $attachment['status']);
+ return $attachment;
}
+
+ return false;
}
@@ -709,7 +707,7 @@
html::a(array(
'href' => "#delete",
'title' => rcube_label('delete'),
- 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%d', this)", JS_OBJECT_NAME, $id)),
+ 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", JS_OBJECT_NAME, $id)),
$button) . Q($a_prop['name']));
}
}
Modified: branches/devel-api/program/steps/mail/sendmail.inc
===================================================================
--- branches/devel-api/program/steps/mail/sendmail.inc 2009-03-17 14:36:00 UTC (rev 2355)
+++ branches/devel-api/program/steps/mail/sendmail.inc 2009-03-17 15:04:05 UTC (rev 2356)
@@ -295,56 +295,55 @@
$transfer_encoding = in_array(strtoupper($message_charset), $charset_7bit) ? '7bit' : '8bit';
// add stored attachments, if any
-if (is_array($_SESSION['compose']['attachments']))
- foreach ($_SESSION['compose']['attachments'] as $id => $attachment)
- {
+if (is_array($_SESSION['compose']['attachments'])) {
+ foreach ($_SESSION['compose']['attachments'] as $id => $attachment) {
// This hook gives attachment handlers a chance to place the file on disk
- $plugin = rcmail::get_instance()->plugins->exec_hook('get_attachment', array('id' => $id,'attachment'=>$attachment));
- $attachment = $plugin['attachment'];
- $dispurl = '/\ssrc\s*=\s*[\'"]?\S+display-attachment\S+file=rcmfile' . $id . '[\'"]?/';
+ $attachment = $RCMAIL->plugins->exec_hook('get_attachment', $attachment);
+
+ $dispurl = '/\ssrc\s*=\s*[\'"]?\S+display-attachment\S+file=rcmfile' . $attachment['id'] . '[\'"]?/';
$match = preg_match($dispurl, $message_body);
- if ($isHtml && ($match > 0))
- {
+ if ($isHtml && ($match > 0)) {
$message_body = preg_replace($dispurl, ' src="'.$attachment['name'].'"', $message_body);
$MAIL_MIME->setHTMLBody($message_body);
- $MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name']);
+ if ($attachment['data'])
+ $MAIL_MIME->addHTMLImage($attachment['data'], $attachment['mimetype'], $attachment['name'], false);
+ else
+ $MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name'], true);
}
- else
- {
+ else {
$ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914
+ $file = $attachment['data'] ? $attachment['data'] : $attachment['path'];
// .eml attachments send inline
- $MAIL_MIME->addAttachment($attachment['path'],
+ $MAIL_MIME->addAttachment($file,
$ctype,
- $attachment['name'], true,
+ $attachment['name'],
+ ($attachment['data'] ? false : true),
($ctype == 'message/rfc822' ? $transfer_encoding : 'base64'),
($ctype == 'message/rfc822' ? 'inline' : 'attachment'),
$message_charset, '', '',
- $CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL,
- $CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL
- );
+ $CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL,
+ $CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL
+ );
}
- if($plugin['erase_after_send']){
- unlink($plugin['attachment']['path']);
- }
}
+}
// add submitted attachments
-if (is_array($_FILES['_attachments']['tmp_name']))
- foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath)
- {
+if (is_array($_FILES['_attachments']['tmp_name'])) {
+ foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) {
$ctype = $files['type'][$i];
$ctype = str_replace('image/pjpeg', 'image/jpeg', $ctype); // #1484914
$MAIL_MIME->addAttachment($filepath, $ctype, $files['name'][$i], true,
- $ctype == 'message/rfc822' ? $transfer_encoding : 'base64',
- 'attachment', $message_charset, '', '',
- $CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL,
- $CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL
- );
- }
+ $ctype == 'message/rfc822' ? $transfer_encoding : 'base64',
+ 'attachment', $message_charset, '', '',
+ $CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL,
+ $CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL
+ );
+ }
+}
-
// encoding settings for mail composing
$MAIL_MIME->setParam(array(
'text_encoding' => $transfer_encoding,
_______________________________________________
http://lists.roundcube.net/mailman/listinfo/svn
More information about the Svn
mailing list