From: Michael M Slusarz Date: Thu, 25 Mar 2010 04:47:23 +0000 (-0600) Subject: IMP redirect compose improvements. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=b52d7646b607b11d6ec24b306f764db6a4995595;p=horde.git IMP redirect compose improvements. [mms] Properly redirect messages pursuant to RFC 5322 [3.6.6]. [mms] Add redirect message capability to DIMP. --- diff --git a/framework/Mime/lib/Horde/Mime/Headers.php b/framework/Mime/lib/Horde/Mime/Headers.php index cbed752a2..edebab265 100644 --- a/framework/Mime/lib/Horde/Mime/Headers.php +++ b/framework/Mime/lib/Horde/Mime/Headers.php @@ -234,22 +234,6 @@ class Horde_Mime_Headers } /** - * Generate the 'Resent' headers (conforms to guidelines in - * RFC 2822 [3.6.6]). - * - * @param string $from The address to use for 'Resent-From'. - * @param string $to The address to use for 'Resent-To'. - */ - public function addResentHeaders($from, $to) - { - /* We don't set Resent-Sender, Resent-Cc, or Resent-Bcc. */ - $this->addHeader('Resent-Date', date('r')); - $this->addHeader('Resent-From', $from); - $this->addHeader('Resent-To', $to); - $this->addHeader('Resent-Message-ID', Horde_Mime::generateMessageId()); - } - - /** * Generate the user agent description header. */ public function addUserAgentHeader() diff --git a/imp/compose-dimp.php b/imp/compose-dimp.php index d075a8266..e9b51b4c0 100644 --- a/imp/compose-dimp.php +++ b/imp/compose-dimp.php @@ -44,9 +44,13 @@ foreach (array('to', 'cc', 'bcc', 'subject') as $v) { $fillform_opts = array('noupdate' => 1); $get_sig = true; -$js = array(); $msg = ''; +$js = array(); +if ($vars->popup) { + $js[] = 'DIMP.conf_compose.popup = 1'; +} + $identity = Horde_Prefs_Identity::singleton(array('imp', 'imp')); if (!$prefs->isLocked('default_identity') && isset($vars->identity)) { $identity->setDefault($vars->identity); @@ -58,14 +62,10 @@ $imp_compose = IMP_Compose::singleton(); /* Init IMP_Ui_Compose:: object. */ $imp_ui = new IMP_Ui_Compose(); -/* Attach spellchecker & auto completer. */ -$imp_ui->attachAutoCompleter(array('to', 'cc', 'bcc')); -$imp_ui->attachSpellChecker(); - $show_editor = false; $title = _("New Message"); -if (in_array($vars->type, array('reply', 'reply_all', 'reply_auto', 'reply_list', 'forward_attach', 'forward_auto', 'forward_body', 'forward_both', 'resume'))) { +if (in_array($vars->type, array('reply', 'reply_all', 'reply_auto', 'reply_list', 'forward_attach', 'forward_auto', 'forward_body', 'forward_both', 'forward_redirect', 'resume'))) { if (!$vars->uid || !$vars->folder) { $vars->type = 'new'; } @@ -134,6 +134,13 @@ case 'forward_both': } break; +case 'forward_redirect': + $imp_compose->redirectMessage($imp_contents); + $get_sig = false; + $title = _("Redirect"); + $vars->type = 'redirect'; + break; + case 'resume': try { $result = $imp_compose->resumeDraft($vars->uid . IMP::IDX_SEP . $vars->folder); @@ -158,15 +165,27 @@ case 'new': break; } -$sig = $identity->getSignature(); -if ($get_sig && !empty($sig)) { - if ($show_editor) { - $sig = '

' . $imp_compose->text2html(trim($sig)) . '

'; +/* Attach spellchecker & auto completer. */ +if ($vars->type == 'redirect') { + $imp_ui->attachAutoCompleter(array('redirect_to')); +} else { + $imp_ui->attachAutoCompleter(array('to', 'cc', 'bcc', 'redirect_to')); + $imp_ui->attachSpellChecker(); + + $sig = $identity->getSignature(); + if ($get_sig && !empty($sig)) { + if ($show_editor) { + $sig = '

' . $imp_compose->text2html(trim($sig)) . '

'; + } + + $msg = ($identity->getValue('sig_first')) + ? "\n" . $sig . $msg + : $msg . "\n" . $sig; } - $msg = ($identity->getValue('sig_first')) - ? "\n" . $sig . $msg - : $msg . "\n" . $sig; + if ($show_editor) { + $js[] = 'DIMP.conf_compose.show_editor = 1'; + } } $t = $injector->createInstance('Horde_Template'); @@ -175,25 +194,17 @@ $t->set('title', $title); $compose_result = IMP_Views_Compose::showCompose(array( 'composeCache' => $imp_compose->getCacheId(), - 'folder' => $vars->folder, - 'qreply' => false, - 'uid' => $vars->uid + 'redirect' => ($vars->type == 'redirect') )); $t->set('compose_html', $compose_result['html']); -/* Javscript variables to be set immediately. */ -if ($show_editor) { - $js[] = 'DIMP.conf_compose.show_editor = 1'; -} -if ($vars->popup) { - $js[] = 'DIMP.conf_compose.popup = 1'; -} Horde::addInlineScript(array_merge($compose_result['js'], $js)); -/* Javascript to be run on window load. */ -$fillform_opts['focus'] = ($vars->type == 'new' || $vars->type == 'forward') ? 'to' : 'composeMessage'; -$compose_result['jsonload'][] = 'DimpCompose.fillForm(' . Horde_Serialize::serialize($msg, Horde_Serialize::JSON) . ',' . Horde_Serialize::serialize($header, Horde_Serialize::JSON) . ',' . Horde_Serialize::serialize($fillform_opts, Horde_Serialize::JSON) . ')'; +$fillform_opts['focus'] = in_array($vars->type, array('forward', 'new', 'redirect')) ? 'to' : 'composeMessage'; +if ($vars->type != 'redirect') { + $compose_result['jsonload'][] = 'DimpCompose.fillForm(' . Horde_Serialize::serialize($msg, Horde_Serialize::JSON) . ',' . Horde_Serialize::serialize($header, Horde_Serialize::JSON) . ',' . Horde_Serialize::serialize($fillform_opts, Horde_Serialize::JSON) . ')'; +} Horde::addInlineScript($compose_result['jsonload'], 'load'); $scripts = array( @@ -204,7 +215,7 @@ $scripts = array( ); IMP::status(); -IMP_Dimp::header(_("Message Composition"), $scripts); +IMP_Dimp::header($title, $scripts); echo $t->fetch(IMP_TEMPLATES . '/dimp/compose/compose.html'); Horde::includeScriptFiles(); Horde::outputInlineScript(); diff --git a/imp/compose-mimp.php b/imp/compose-mimp.php index 6a71a3e4c..2c9f54b5c 100644 --- a/imp/compose-mimp.php +++ b/imp/compose-mimp.php @@ -38,6 +38,7 @@ $vars = Horde_Variables::getDefaultVariables(); $expand = array(); $header = array('to' => '', 'cc' => '', 'bcc' => ''); $msg = ''; +$title = _("Compose Message"); /* Get the list of headers to display. */ $display_hdrs = array('to' => _("To: ")); @@ -150,6 +151,7 @@ case 'rl': $header = $reply_msg['headers']; $notification->push(_("Reply text will be automatically appended to your outgoing message."), 'horde.message'); + $title = _("Reply"); break; // 'f' = forward @@ -161,17 +163,24 @@ case 'f': $header = $fwd_msg['headers']; $notification->push(_("Forwarded message will be automatically added to your outgoing message."), 'horde.message'); + $title = _("Forward"); break; -case _("Redirect"): - if (!($imp_contents = $imp_ui->getIMPContents($imp_compose->getMetadata('uid'), $imp_compose->getMetadata('mailbox')))) { +// 'rc' = redirect compose +case 'rc': + $title = _("Redirect"); + if (!($imp_contents = $imp_ui->getIMPContents($imp_mbox['uid'], $imp_mbox['thismailbox']))) { + // TODO: Error message break; } + $imp_compose->redirectMessage($imp_contents); + break; - $f_to = $imp_ui->getAddressList($header['to']); - +case _("Redirect"): try { - $imp_ui->redirectMessage($f_to, $imp_compose, $imp_contents); + $imp_compose->sendRedirectMessage($imp_ui->getAddressList($header['to'])); + $imp_compose->destroy('send'); + if ($prefs->getValue('compose_confirm')) { $notification->push(_("Message redirected successfully."), 'horde.success'); } @@ -302,8 +311,8 @@ $t->set('to', htmlspecialchars($header['to'])); $t->set('url', Horde::applicationUrl('compose-mimp.php')); if ($vars->a == 'rc') { + $t->set('redirect', true); unset($display_hdrs['cc'], $display_hdrs['bcc']); - $title = _("Redirect"); } else { $t->set('compose_enable', !$compose_disable); $t->set('msg', htmlspecialchars($msg)); diff --git a/imp/compose.php b/imp/compose.php index 0a3ceb92f..d0b845709 100644 --- a/imp/compose.php +++ b/imp/compose.php @@ -307,18 +307,17 @@ case 'forward_both': break; case 'redirect_compose': - $title = _("Redirect this message"); - break; - -case 'redirect_send': if (!($imp_contents = $imp_ui->getIMPContents($uid, $thismailbox))) { break; } + $imp_compose->redirectMessage($imp_contents); + $title = _("Redirect"); + break; - $f_to = $imp_ui->getAddressList($vars->to); - +case 'redirect_send': try { - $imp_ui->redirectMessage($f_to, $imp_compose, $imp_contents); + $imp_compose->sendRedirectMessage($imp_ui->getAddressList($vars->to)); + $imp_compose->destroy('send'); if ($isPopup) { if ($prefs->getValue('compose_confirm')) { @@ -714,8 +713,7 @@ $t->set('allow_compose', !$compose_disable); if ($redirect) { /* Prepare the redirect template. */ - $t->set('mailbox', htmlspecialchars($thismailbox)); - $t->set('uid', htmlspecialchars($uid)); + $t->set('cacheid', $composeCacheID); $t->set('status', Horde_Util::bufferOutput(array('IMP', 'status'))); $t->set('title', htmlspecialchars($title)); $t->set('token', Horde::getRequestToken('imp.compose')); diff --git a/imp/docs/CHANGES b/imp/docs/CHANGES index e802fa3ea..31e6d1afa 100644 --- a/imp/docs/CHANGES +++ b/imp/docs/CHANGES @@ -2,6 +2,8 @@ v5.0-git -------- +[mms] Properly redirect messages pursuant to RFC 5322 [3.6.6]. +[mms] Add redirect message capability to DIMP. [mms] Add ability to add attachments to composed messages for advanced mobile browsers - disabled by default (MIMP). [mms] Add checkbox interface to mailbox page for advanced mobile browsers - diff --git a/imp/js/DimpBase.js b/imp/js/DimpBase.js index 9fbfce370..5fd7cb6db 100644 --- a/imp/js/DimpBase.js +++ b/imp/js/DimpBase.js @@ -810,6 +810,7 @@ var DimpBase = { case 'ctx_forward_attach': case 'ctx_forward_body': case 'ctx_forward_both': + case 'ctx_forward_redirect': this.composeMailbox(id.substring(4)); break; @@ -2952,9 +2953,7 @@ var DimpBase = { this._addMouseEvents({ id: 'folderopts', type: 'folderopts' }, $('folderopts').down(1)); DM.addSubMenu('ctx_message_reply', 'ctx_reply'); - if ($('ctx_forward')) { - DM.addSubMenu('ctx_message_forward', 'ctx_forward'); - } + DM.addSubMenu('ctx_message_forward', 'ctx_forward'); [ 'ctx_message_', 'oa_' ].each(function(i) { if ($(i + 'setflag')) { DM.addSubMenu(i + 'setflag', 'ctx_flag'); @@ -2969,10 +2968,8 @@ var DimpBase = { this._addMouseEvents({ id: 'button_reply', type: 'reply' }, $('button_reply')); DM.disable('button_reply_img', true, true); - if ($('ctx_forward')) { - this._addMouseEvents({ id: 'button_forward', type: 'forward' }, $('button_forward')); - DM.disable('button_forward_img', true, true); - } + this._addMouseEvents({ id: 'button_forward', type: 'forward' }, $('button_forward')); + DM.disable('button_forward_img', true, true); } new Drop('dropbase', this._folderDropConfig); diff --git a/imp/js/compose-dimp.js b/imp/js/compose-dimp.js index 24f0547dd..fb031db89 100644 --- a/imp/js/compose-dimp.js +++ b/imp/js/compose-dimp.js @@ -138,7 +138,9 @@ var DimpCompose = { uniqueSubmit: function(action) { - var c = $('compose'); + var c = (action == 'redirectMessage') + ? $('redirect') + : $('compose'); if (DIMP.SpellChecker && DIMP.SpellChecker.isActive()) { @@ -196,7 +198,7 @@ var DimpCompose = { // Can't disable until we send the message - or else nothing // will get POST'ed. - if (action == 'sendMessage' || action == 'saveDraft') { + if (action != 'autoSaveDraft') { this.setDisabled(true); } } @@ -259,6 +261,19 @@ var DimpCompose = { } return this.closeCompose(); + case 'redirectMessage': + if (this.is_popup && DIMP.baseWindow.DimpBase) { + if (d.log) { + DIMP.baseWindow.DimpBase.updateMsgLog(d.log, { uid: d.uid, mailbox: d.mbox }); + } + + if (!DIMP.conf_compose.qreply) { + DIMP.baseWindow.DimpCore.showNotifications(r.msgs); + r.msgs = []; + } + } + return this.closeCompose(); + case 'addAttachment': this.uploading = false; if (d.success) { @@ -281,20 +296,27 @@ var DimpCompose = { } this.setDisabled(false); - $('compose').setStyle({ cursor: null }); + + $((d.action == 'redirectMessage') ? 'redirect' : 'compose').setStyle({ cursor: null }); }, setDisabled: function(disable) { this.disabled = disable; - DimpCore.loadingImg('sendingImg', 'composeMessageParent', disable); - DimpCore.toggleButtons($('compose').select('DIV.dimpActions A'), disable); - [ $('compose') ].invoke(disable ? 'disable' : 'enable'); - if (DIMP.SpellChecker) { - DIMP.SpellChecker.disable(disable); - } - if (IMP_Compose_Base.editor_on) { - this.RTELoading(disable ? 'show' : 'hide', true); + + if ($('redirect').visible()) { + DimpCore.loadingImg('sendingImg', 'redirect', disable); + DimpCore.toggleButtons($('redirect').select('DIV.dimpActions A'), disable); + } else { + DimpCore.loadingImg('sendingImg', 'composeMessageParent', disable); + DimpCore.toggleButtons($('compose').select('DIV.dimpActions A'), disable); + [ $('compose') ].invoke(disable ? 'disable' : 'enable'); + if (DIMP.SpellChecker) { + DIMP.SpellChecker.disable(disable); + } + if (IMP_Compose_Base.editor_on) { + this.RTELoading(disable ? 'show' : 'hide', true); + } } }, @@ -425,11 +447,13 @@ var DimpCompose = { if (DIMP.conf_compose.auto_save_interval_val && !this.auto_save_interval) { this.auto_save_interval = new PeriodicalExecuter(function() { - var curr_hash = MD5.hash($('to', 'cc', 'bcc', 'subject').invoke('getValue').join('\0') + (IMP_Compose_Base.editor_on ? this.rte.getData() : $F('composeMessage'))); - if (this.last_msg && curr_hash != this.last_msg) { - this.uniqueSubmit('autoSaveDraft'); + if ($('compose').visible()) { + var curr_hash = MD5.hash($('to', 'cc', 'bcc', 'subject').invoke('getValue').join('\0') + (IMP_Compose_Base.editor_on ? this.rte.getData() : $F('composeMessage'))); + if (this.last_msg && curr_hash != this.last_msg) { + this.uniqueSubmit('autoSaveDraft'); + } + this.last_msg = curr_hash; } - this.last_msg = curr_hash; }.bind(this), DIMP.conf_compose.auto_save_interval_val * 60); /* Immediately execute to get MD5 hash of empty message. */ this.auto_save_interval.execute(); @@ -662,9 +686,15 @@ var DimpCompose = { }, /* Open the addressbook window. */ - openAddressbook: function() + openAddressbook: function(params) { - window.open(DIMP.conf_compose.URI_ABOOK, 'contacts', 'toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes,width=550,height=300,left=100,top=100'); + var uri = DIMP.conf_compose.URI_ABOOK; + + if (params) { + uri = DimpCore.addURLParam(uri, params); + } + + window.open(uri, 'contacts', 'toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes,width=550,height=300,left=100,top=100'); }, /* Click observe handler. */ @@ -693,9 +723,20 @@ var DimpCompose = { break; case 'draft_button': + if (!this.disabled) { + this.uniqueSubmit('saveDraft'); + } + break; + case 'send_button': if (!this.disabled) { - this.uniqueSubmit(id == 'send_button' ? 'sendMessage' : 'saveDraft'); + this.uniqueSubmit('sendMessage'); + } + break; + + case 'send_button_redirect': + if (!this.disabled) { + this.uniqueSubmit('redirectMessage'); } break; @@ -708,6 +749,16 @@ var DimpCompose = { } break; + case 'redirect_sendto': + if (orig.match('TD.label SPAN')) { + this.openAddressbook({ + formfield: 'redirect_to', + formname: 'redirect', + to_only: 1 + }); + } + break; + case 'sendcc': case 'sendbcc': case 'sendto': @@ -782,6 +833,20 @@ var DimpCompose = { this.is_popup = (DIMP.baseWindow && DIMP.baseWindow.DimpBase); + /* Initialize redirect elements (always needed). */ + $('redirect').observe('submit', Event.stop); + new TextareaResize('redirect_to'); + if (DIMP.conf_compose.URI_ABOOK) { + $('redirect_sendto').down('TD.label SPAN').addClassName('composeAddrbook'); + } + + /* Nothing more to do if this is strictly a redirect window. */ + if (DIMP.conf_compose.redirect) { + $('dimpLoading').hide(); + $('redirect', 'pageContainer').invoke('show'); + return; + } + /* Attach event handlers. */ document.observe('change', this.changeHandler.bindAsEventListener(this)); Event.observe(window, 'resize', this.resizeMsgArea.bind(this)); @@ -795,18 +860,6 @@ var DimpCompose = { document.observe('SpellChecker:before', this._onSpellCheckBefore.bind(this)); } - // Automatically resize address fields. - new TextareaResize('to'); - new TextareaResize('cc'); - new TextareaResize('bcc'); - - /* Add addressbook link formatting. */ - if (DIMP.conf_compose.URI_ABOOK) { - $('sendto', 'sendcc', 'sendbcc').each(function(a) { - a.down('TD.label SPAN').addClassName('composeAddrbook'); - }); - } - /* Create folderlist. */ if (DIMP.conf_compose.flist) { this.knl_sm = new KeyNavList('save_sent_mail', { @@ -829,6 +882,18 @@ var DimpCompose = { $('priority_label').insert({ after: new Element('SPAN', { className: 'popdownImg' }).observe('click', function(e) { if (!this.disabled) { this.knl_p.show(); this.knl_p.ignoreClick(e); e.stop(); } }.bindAsEventListener(this)) }); } + // Automatically resize compose address fields. + new TextareaResize('to'); + new TextareaResize('cc'); + new TextareaResize('bcc'); + + /* Add addressbook link formatting. */ + if (DIMP.conf_compose.URI_ABOOK) { + $('sendto', 'sendcc', 'sendbcc', 'redirect_sendto').each(function(a) { + a.down('TD.label SPAN').addClassName('composeAddrbook'); + }); + } + $('dimpLoading').hide(); $('pageContainer').show(); diff --git a/imp/js/fullmessage-dimp.js b/imp/js/fullmessage-dimp.js index d9316ccb2..f5bf5ce26 100644 --- a/imp/js/fullmessage-dimp.js +++ b/imp/js/fullmessage-dimp.js @@ -13,14 +13,13 @@ var DimpFullmessage = { var func, ob = {}; ob[this.mailbox] = [ this.uid ]; - $('msgData').hide(); - $('qreply').show(); - switch (type) { case 'reply': case 'reply_all': case 'reply_auto': case 'reply_list': + $('compose').show(); + $('redirect').hide(); func = 'getReplyData'; break; @@ -28,10 +27,21 @@ var DimpFullmessage = { case 'forward_attach': case 'forward_body': case 'forward_both': + $('compose').show(); + $('redirect').hide(); func = 'getForwardData'; break; + + case 'forward_redirect': + $('compose').hide(); + $('redirect').show(); + func = 'getRedirectData'; + break; } + $('msgData').hide(); + $('qreply').show(); + DimpCore.doAction(func, { imp_compose: $F('composeCache'), type: type }, @@ -45,24 +55,28 @@ var DimpFullmessage = { return; } - var i, - r = result.response, - id = (r.identity === null) ? $F('identity') : r.identity; + var i, id, + r = result.response; - if (!r.opts) { - r.opts = {}; - } - r.opts.noupdate = true; - r.opts.show_editor = (r.format == 'html'); + if (r.type == 'forward_redirect') { + $('redirect_composeCache').setValue(r.imp_compose); + } else { + if (!r.opts) { + r.opts = {}; + } + r.opts.noupdate = true; + r.opts.show_editor = (r.format == 'html'); - i = IMP_Compose_Base.getIdentity(id, r.opts.show_editor); + id = (r.identity === null) ? $F('identity') : r.identity; + i = IMP_Compose_Base.getIdentity(id, r.opts.show_editor); - $('identity', 'last_identity').invoke('setValue', id); + $('identity', 'last_identity').invoke('setValue', id); - DimpCompose.fillForm((i.id[2]) ? ("\n" + i.sig + r.body) : (r.body + "\n" + i.sig), r.header, r.opts); + DimpCompose.fillForm((i.id[2]) ? ("\n" + i.sig + r.body) : (r.body + "\n" + i.sig), r.header, r.opts); - if (r.imp_compose) { - $('composeCache').setValue(r.imp_compose); + if (r.imp_compose) { + $('composeCache').setValue(r.imp_compose); + } } }, @@ -157,6 +171,7 @@ var DimpFullmessage = { case 'ctx_forward_attach': case 'ctx_forward_body': case 'ctx_forward_both': + case 'ctx_forward_redirect': this.quickreply(id.substring(4)); break; @@ -190,9 +205,7 @@ var DimpFullmessage = { tmp = $('reply_link', 'forward_link').compact().invoke('up', 'SPAN').concat([ $('ctx_contacts_new') ]).compact().invoke('remove'); } else { this.addPopdown('reply_link', 'replypopdown'); - if ($('ctx_forwardpopdown')) { - this.addPopdown('forward_link', 'forwardpopdown'); - } + this.addPopdown('forward_link', 'forwardpopdown'); } /* Set up address linking. */ diff --git a/imp/lib/Ajax/Application.php b/imp/lib/Ajax/Application.php index 13c7e826b..552e1b10f 100644 --- a/imp/lib/Ajax/Application.php +++ b/imp/lib/Ajax/Application.php @@ -940,12 +940,7 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base public function getForwardData() { try { - $imp_compose = IMP_Compose::singleton($this->_vars->imp_compose); - if (!($imp_contents = $imp_compose->getContentsOb())) { - $indices = $GLOBALS['imp_imap']->ob()->utils->fromSequenceString($this->_vars->uid); - $i = each($indices); - $imp_contents = IMP_Contents::singleton(reset($i['value']) . IMP::IDX_SEP . $i['key']); - } + list($imp_compose, $imp_contents) = $this->_initCompose(); $fwd_msg = $imp_compose->forwardMessage($this->_vars->type, $imp_contents); @@ -997,18 +992,14 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base * 'identity' - (integer) The identity ID to use for this message. * 'imp_compose' - (string) The IMP_Compose cache identifier. * 'opts' - (array) Additional options needed for DimpCompose.fillForm(). + * 'type' - (string) The input 'type' value. * 'ViewPort' - (object) See _viewPortData(). * */ public function getReplyData() { try { - $imp_compose = IMP_Compose::singleton($this->_vars->imp_compose); - if (!($imp_contents = $imp_compose->getContentsOb())) { - $indices = $GLOBALS['imp_imap']->ob()->utils->fromSequenceString($this->_vars->uid); - $i = each($indices); - $imp_contents = IMP_Contents::singleton(reset($i['value']) . IMP::IDX_SEP . $i['key']); - } + list($imp_compose, $imp_contents) = $this->_initCompose(); $reply_msg = $imp_compose->replyMessage($this->_vars->type, $imp_contents); $reply_msg['headers']['replytype'] = 'reply'; @@ -1017,6 +1008,7 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base * cache id. */ $result = new stdClass; $result->header = $reply_msg['headers']; + $result->type = $this->_vars->type; if (!$this->_vars->headeronly) { $result->body = $reply_msg['body']; $result->format = $reply_msg['format']; @@ -1035,6 +1027,35 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base } /** + * AJAX action: Get compose redirect data. + * + * Variables used: + *
+     * 'uid' - (string) Index of the message to redirect (IMAP sequence
+     *         string).
+     * 
+ * + * @return mixed False on failure, or an object with the following + * entries: + *
+     * 'imp_compose' - (string) The IMP_Compose cache identifier.
+     * 'type' - (string) The input 'type' value.
+     * 
+ */ + public function getRedirectData() + { + list($imp_compose, $imp_contents) = $this->_initCompose(); + + $imp_compose->redirectMessage($imp_contents); + + $ob = new stdClass; + $ob->imp_compose = $imp_compose->getCacheId(); + $ob->type = $this->_vars->type; + + return $ob; + } + + /** * AJAX action: Cancel compose. * * Variables used: @@ -1401,6 +1422,56 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base } /** + * Redirect the message. + * + * Variables used: + *
+     * 'redirect_composeCache' - (string) The IMP_Compose cache identifier.
+     * 'redirect_to' - (string) The address(es) to redirect to.
+     * 
+ * + * @return object An object with the following entries: + *
+     * 'log' - (array) TODO
+     * 'mbox' - (array) TODO
+     * 'success' - (integer) 1 on success, 0 on failure.
+     * 'uid' - (integer) TODO
+     * 
+ */ + public function redirectMessage() + { + $result = new stdClass; + $result->action = $this->_action; + $result->success = 1; + + try { + $imp_compose = IMP_Compose::singleton($this->_vars->redirect_composeCache); + $imp_compose->sendRedirectMessage($this->_vars->redirect_to); + + $result->mbox = $imp_compose->getMetadata('mailbox'); + $result->uid = $imp_compose->getMetadata('uid'); + + $contents = $imp_compose->getContentsOb(); + $headers = $contents->getHeaderOb(); + + if ($GLOBALS['prefs']->getValue('compose_confirm')) { + $subject = $headers->getValue('subject'); + $GLOBALS['notification']->push(empty($subject) ? _("Message redirected successfully.") : sprintf(_("Message \"%s\" redirected successfully."), Horde_String::truncate($subject)), 'horde.success'); + } + + if (!empty($GLOBALS['conf']['maillog']['use_maillog']) && + ($tmp = IMP_Dimp::getMsgLogInfo($headers->getValue('message-id')))) { + $result->log = $tmp; + } + } catch (Horde_Exception $e) { + $GLOBALS['notification']->push($e); + $result->success = 0; + } + + return $result; + } + + /** * Setup environment for dimp compose actions. * * Variables used: @@ -1458,6 +1529,21 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base } /** + * TODO + */ + protected function _initCompose() + { + $imp_compose = IMP_Compose::singleton($this->_vars->imp_compose); + if (!($imp_contents = $imp_compose->getContentsOb())) { + $indices = $GLOBALS['imp_imap']->ob()->utils->fromSequenceString($this->_vars->uid); + $i = each($indices); + $imp_contents = IMP_Contents::singleton(reset($i['value']) . IMP::IDX_SEP . $i['key']); + } + + return array($imp_compose, $imp_contents); + } + + /** * Save a draft composed message. * * See the list of variables needed for _dimpComposeSetup(). Additional @@ -1584,7 +1670,7 @@ class IMP_Ajax_Application extends Horde_Ajax_Application_Base * 'view' - (string) The current ViewPort view (mailbox). * * - * @param boolean $rw Open mailbox as READ+WRITE? + * @param boolean $rw Open mailbox as READ+WRITE? * * @return boolean True if the server state differs from the browser * state. diff --git a/imp/lib/Compose.php b/imp/lib/Compose.php index 10f67a4bf..6859287c4 100644 --- a/imp/lib/Compose.php +++ b/imp/lib/Compose.php @@ -748,9 +748,10 @@ class IMP_Compose $email = $this->_prepSendMessage($email, $headers, $message); $mail_driver = $this->getMailDriver(); - $mailer = Mail::factory($mail_driver['driver'], $mail_driver['params']); - if ($mailer instanceof PEAR_Error) { - throw new IMP_Compose_Exception($mailer); + try { + $mailer = Horde_Mime_Mail::getMailOb($mail_driver['driver'], $mail_driver['params']); + } catch (Horde_Mime_Exception $e) { + throw new IMP_Compose_Exception($e); } try { @@ -850,7 +851,10 @@ class IMP_Compose $params['password'] = $GLOBALS['imp_imap']->ob()->getParam('password'); } - return array('driver' => $GLOBALS['conf']['mailer']['type'], 'params' => $params); + return array( + 'driver' => $GLOBALS['conf']['mailer']['type'], + 'params' => $params + ); } /** @@ -1640,6 +1644,74 @@ class IMP_Compose } /** + * Prepare a redirect message. + * + * @param IMP_Contents $contents An IMP_Contents object. + */ + public function redirectMessage($contents) + { + $this->_metadata['mailbox'] = $contents->getMailbox(); + $this->_metadata['reply_type'] = 'redirect'; + $this->_metadata['uid'] = $contents->getUid(); + $this->_modified = true; + } + + /** + * Send a redirect (a/k/a resent) message. See RFC 5322 [3.6.6]. + * + * @param string $to The addresses to redirect to. + * + * @throws IMP_Compose_Exception + */ + public function sendRedirectMessage($to) + { + $recip = $this->recipientList(array('to' => $to)); + $recipients = implode(', ', $recip['list']); + + $identity = Horde_Prefs_Identity::singleton(array('imp', 'imp')); + $from_addr = $identity->getFromAddress(); + + $contents = $this->getContentsOb(); + $headers = $contents->getHeaderOb(); + + /* Generate the 'Resent' headers (RFC 5322 [3.6.6]). These headers are + * prepended to the message. */ + $resent_headers = new Horde_Mime_Headers(); + $resent_headers->addHeader('Resent-Date', date('r')); + $resent_headers->addHeader('Resent-From', $from_addr); + $resent_headers->addHeader('Resent-To', $recip['header']['to']); + $resent_headers->addHeader('Resent-Message-ID', Horde_Mime::generateMessageId()); + + $header_text = trim($resent_headers->toString(array('encode' => Horde_Nls::getCharset()))) . "\n" . trim($contents->getHeaderOb(false)); + + $mail_driver = $this->getMailDriver(); + try { + $mailer = Horde_Mime_Mail::getMailOb($mail_driver['driver'], $mail_driver['params'], array('raw' => array('from' => $headers->getValue('from'), 'headertext' => $header_text))); + } catch (Horde_Mime_Exception $e) { + throw new IMP_Compose_Exception($e); + } + + $to = $this->_prepSendMessage($recipients); + + try { + Horde_Mime_Mail::sendPearMail($mailer, $to, $headers->toArray(array('charset' => Horde_Nls::getCharset())), $contents->getBody()); + } catch (Horde_Mime_Exception $e) { + throw new IMP_Compose_Exception($e); + } + + Horde::logMessage(sprintf("%s Redirected message sent to %s from %s", $_SERVER['REMOTE_ADDR'], $recipients, Horde_Auth::getAuth()), 'INFO'); + + /* Store history information. */ + if (!empty($GLOBALS['conf']['maillog']['use_maillog'])) { + IMP_Maillog::log('redirect', $headers->getValue('message-id'), $recipients); + } + + if ($GLOBALS['conf']['sentmail']['driver'] != 'none') { + $GLOBALS['injector']->getInstance('IMP_Sentmail')>log('redirect', $headers->getValue('message-id'), $recipients); + } + } + + /** * Get "tieto" identity information. * * @param Horde_Mime_Headers $h The headers object for the message. @@ -1653,8 +1725,7 @@ class IMP_Compose $msgAddresses[] = $h->getValue($val); } - $user_identity = Horde_Prefs_Identity::singleton(array('imp', 'imp')); - return $user_identity->getMatchingIdentity($msgAddresses); + return Horde_Prefs_Identity::singleton(array('imp', 'imp'))->getMatchingIdentity($msgAddresses); } /** diff --git a/imp/lib/Contents.php b/imp/lib/Contents.php index 3cea778d4..bb47e04c8 100644 --- a/imp/lib/Contents.php +++ b/imp/lib/Contents.php @@ -307,9 +307,13 @@ class IMP_Contents /** * Returns the header object. * - * @return Horde_Mime_Headers The Horde_Mime_Headers object. + * @param boolean $parse Parse the headers into a headers object? + * + * @return Horde_Mime_Headers|string Either a Horde_Mime_Headers object + * (if $parse is true) or the header + * text (if $parse is false). */ - public function getHeaderOb() + public function getHeaderOb($parse = true) { if (is_null($this->_message)) { return $this->_message->getMIMEHeaders(); @@ -317,11 +321,13 @@ class IMP_Contents try { $res = $GLOBALS['imp_imap']->ob()->fetch($this->_mailbox, array( - Horde_Imap_Client::FETCH_HEADERTEXT => array(array('parse' => true, 'peek' => true)) + Horde_Imap_Client::FETCH_HEADERTEXT => array(array('parse' => $parse, 'peek' => true)) ), array('ids' => array($this->_uid))); return $res[$this->_uid]['headertext'][0]; } catch (Horde_Imap_Client_Exception $e) { - return new Horde_Mime_Headers(); + return $parse + ? new Horde_Mime_Headers() + : ''; } } @@ -345,7 +351,7 @@ class IMP_Contents * bodypart from the server. * DEFAULT: All data is retrieved. * 'nocontents' - (boolean) If true, don't add the contents to the part - * DEFAULT: Contents are added to the part + * DEFAULT: Contents are added to the part * * * @return Horde_Mime_Part The raw MIME part asked for (reference). diff --git a/imp/lib/Ui/Compose.php b/imp/lib/Ui/Compose.php index 86db14ea2..bdddb098c 100644 --- a/imp/lib/Ui/Compose.php +++ b/imp/lib/Ui/Compose.php @@ -63,55 +63,6 @@ class IMP_Ui_Compose } /** - * Redirect a message. - * - * @param string $to The To address. - * @param IMP_Compose $imp_compose An IMP_Compose object. - * @param IMP_Contents $imp_contents An IMP_Contents object. - * - * @throws Horde_Exception - */ - public function redirectMessage($to, $imp_compose, $contents) - { - try { - $recip = $imp_compose->recipientList(array('to' => $to)); - } catch (IMP_Compose_Exception $e) { - throw new Horde_Exception_Prior($recip); - } - $recipients = implode(', ', $recip['list']); - - $identity = Horde_Prefs_Identity::singleton(array('imp', 'imp')); - $from_addr = $identity->getFromAddress(); - - $headers = $contents->getHeaderOb(); - $headers->addResentHeaders($from_addr, $recip['header']['to']); - - $mime_message = $contents->getMIMEMessage(); - - /* We need to set the Return-Path header to the current user - see - RFC 2821 [4.4]. */ - $headers->removeHeader('return-path'); - $headers->addHeader('Return-Path', $from_addr); - - /* Store history information. */ - if (!empty($GLOBALS['conf']['maillog']['use_maillog'])) { - IMP_Maillog::log('redirect', $headers->getValue('message-id'), $recipients); - } - - try { - $imp_compose->sendMessage($recipients, $headers, $mime_message); - } catch (IMP_Compose_Exception $e) { - throw new Horde_Exception_Prior($e); - } - - $entry = sprintf("%s Redirected message sent to %s from %s", - $_SERVER['REMOTE_ADDR'], $recipients, Horde_Auth::getAuth()); - Horde::logMessage($entry, 'INFO'); - - $GLOBALS['injector']->getInstance('IMP_Sentmail')>log('redirect', $headers->getValue('message-id'), $recipients); - } - - /** * Attach the auto-completer to the current compose form. * * @param array $fields The list of DOM IDs to attach the autocompleter diff --git a/imp/lib/Views/Compose.php b/imp/lib/Views/Compose.php index c53bccdfa..470b81228 100644 --- a/imp/lib/Views/Compose.php +++ b/imp/lib/Views/Compose.php @@ -16,8 +16,9 @@ class IMP_Views_Compose * * @param array $args Configuration parameters: *
-     * 'composeCache' - The cache ID of the IMP_Compose object.
-     * 'qreply' - Is this a quickreply view?
+     * 'composeCache' - (string) The cache ID of the IMP_Compose object.
+     * 'redirect' - (string) Display the redirect interface?
+     * 'qreply' - (boolean) Is this a quickreply view?
      * 
* * @return array Array with the following keys: @@ -31,67 +32,75 @@ class IMP_Views_Compose { $result = array( 'html' => '', - 'jsappend' => '', + 'js' => array(), 'jsonload' => array() ); - /* Load Identity. */ - $identity = Horde_Prefs_Identity::singleton(array('imp', 'imp')); - $selected_identity = $identity->getDefault(); + $compose_html = $redirect = $rte = false; - /* Generate identities list. */ - $imp_ui = new IMP_Ui_Compose(); - $result['js'] = array($imp_ui->identityJs()); - - $composeCache = null; - if (!empty($args['composeCache'])) { + if (empty($args['composeCache'])) { + $composeCache = null; + } else { $imp_compose = IMP_Compose::singleton($args['composeCache']); $composeCache = $args['composeCache']; + } + + if (empty($args['redirect'])) { + /* Load Identity. */ + $identity = Horde_Prefs_Identity::singleton(array('imp', 'imp')); + $selected_identity = $identity->getDefault(); - if ($imp_compose->numberOfAttachments()) { + /* Generate identities list. */ + $imp_ui = $GLOBALS['injector']->getInstance('IMP_Ui_Compose'); + $result['js'][] = $imp_ui->identityJs(); + + if ($composeCache && + $imp_compose->numberOfAttachments()) { foreach ($imp_compose->getAttachments() as $num => $atc) { $mime = $atc['part']; $result['jsonload'][] = 'DimpCompose.addAttach(' . $num . ', \'' . addslashes($mime->getName(true)) . '\', \'' . addslashes($mime->getType()) . '\', \'' . addslashes($mime->getSize()) . "')"; } } - } - if (!empty($args['qreply'])) { - $result['js'][] = 'DIMP.conf_compose.qreply = 1'; - } + if (!empty($args['qreply'])) { + $result['js'][] = 'DIMP.conf_compose.qreply = 1'; + } - $compose_html = $rte = false; - if ($_SESSION['imp']['rteavail']) { - $compose_html = $GLOBALS['prefs']->getValue('compose_html'); - $rte = true; + if ($_SESSION['imp']['rteavail']) { + $compose_html = $GLOBALS['prefs']->getValue('compose_html'); + $rte = true; - $imp_ui->initRTE(!$compose_html); - } + $imp_ui->initRTE(!$compose_html); + } - /* Create list for sent-mail selection. */ - if (!empty($GLOBALS['conf']['user']['select_sentmail_folder']) && - !$GLOBALS['prefs']->isLocked('sent_mail_folder')) { - $imp_folder = $GLOBALS['injector']->getInstance('IMP_Folder'); + /* Create list for sent-mail selection. */ + if (!empty($GLOBALS['conf']['user']['select_sentmail_folder']) && + !$GLOBALS['prefs']->isLocked('sent_mail_folder')) { + $imp_folder = $GLOBALS['injector']->getInstance('IMP_Folder'); - /* Check to make sure the sent-mail folders are created - they - * need to exist to show up in drop-down list. */ - foreach (array_keys($identity->getAllSignatures()) as $ident) { - $val = $identity->getValue('sent_mail_folder', $ident); - if (!$imp_folder->exists($val)) { - $imp_folder->create($val, true); + /* Check to make sure the sent-mail folders are created - they + * need to exist to show up in drop-down list. */ + foreach (array_keys($identity->getAllSignatures()) as $ident) { + $val = $identity->getValue('sent_mail_folder', $ident); + if (!$imp_folder->exists($val)) { + $imp_folder->create($val, true); + } } - } - $flist = array(); - foreach ($imp_folder->flist() as $val) { - $tmp = array('l' => $val['abbrev'], 'v' => $val['val']); - $tmp2 = IMP::displayFolder($val['val']); - if ($val['val'] != $tmp2) { - $tmp['f'] = $tmp2; + $flist = array(); + foreach ($imp_folder->flist() as $val) { + $tmp = array('l' => $val['abbrev'], 'v' => $val['val']); + $tmp2 = IMP::displayFolder($val['val']); + if ($val['val'] != $tmp2) { + $tmp['f'] = $tmp2; + } + $flist[] = $tmp; } - $flist[] = $tmp; + $result['js'][] = 'DIMP.conf_compose.flist = ' . Horde_Serialize::serialize($flist, Horde_Serialize::JSON); } - $result['js'][] = 'DIMP.conf_compose.flist = ' . Horde_Serialize::serialize($flist, Horde_Serialize::JSON); + } else { + $result['js'][] = 'DIMP.conf_compose.redirect = 1'; + $redirect = true; } // Buffer output so that we can return a string from this function diff --git a/imp/message-dimp.php b/imp/message-dimp.php index 69b2ef24f..66add4654 100644 --- a/imp/message-dimp.php +++ b/imp/message-dimp.php @@ -69,7 +69,7 @@ if (!$disable_compose) { /* Attach spellchecker & auto completer. */ $imp_ui = new IMP_Ui_Compose(); - $imp_ui->attachAutoCompleter(array('to', 'cc', 'bcc')); + $imp_ui->attachAutoCompleter(array('to', 'cc', 'bcc', 'redirect_to')); $imp_ui->attachSpellChecker(); $js_out = array_merge($js_out, $compose_result['js']); diff --git a/imp/templates/dimp/chunks/compose.php b/imp/templates/dimp/chunks/compose.php index 32ec64c77..1366e7077 100644 --- a/imp/templates/dimp/chunks/compose.php +++ b/imp/templates/dimp/chunks/compose.php @@ -19,6 +19,7 @@ $save_attach = $GLOBALS['prefs']->getValue('save_attachments'); $compose_disable = !IMP::canCompose(); ?> +
@@ -140,6 +141,28 @@ $compose_disable = !IMP::canCompose();
+ + + + + diff --git a/imp/templates/dimp/chunks/message.php b/imp/templates/dimp/chunks/message.php index b0a4a8ed4..03065e69f 100644 --- a/imp/templates/dimp/chunks/message.php +++ b/imp/templates/dimp/chunks/message.php @@ -124,13 +124,15 @@ -isLocked('forward_default')): ?> +
+ + -isLocked('forward_default')): ?> +
+ +