560 lines
19 KiB
PHP
560 lines
19 KiB
PHP
<?php
|
|
/**
|
|
* Compose page for minimal view.
|
|
*
|
|
* Copyright 2012-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file COPYING for license information (GPL). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/gpl.
|
|
*
|
|
* @author Michael Slusarz <slusarz@horde.org>
|
|
* @category Horde
|
|
* @license http://www.horde.org/licenses/gpl GPL
|
|
* @package IMP
|
|
*/
|
|
class IMP_Minimal_Compose extends IMP_Minimal_Base
|
|
{
|
|
/**
|
|
* URL Parameters:
|
|
* - a: (string) The action ID.
|
|
* - action: (string) The action ID (used on redirect page).
|
|
* - bcc: (string) BCC address(es).
|
|
* - bcc_expand_[1-5]: (string) Expand matches for BCC addresses.
|
|
* - cc: (string) CC address(es).
|
|
* - cc_expand_[1-5]: (string) Expand matches for BCC addresses.
|
|
* - composeCache: (string) Compose object cache ID.
|
|
* - from: (string) From address to use.
|
|
* - identity: (integer) The identity to use for composing.
|
|
* - message: (string) Message text.
|
|
* - subject: (string) Message subject.
|
|
* - to: (string) To address(es).
|
|
* - to_expand_[1-5]: (string) Expand matches for To addresses.
|
|
* - u: (string) Unique ID (cache buster).
|
|
*/
|
|
protected function _init()
|
|
{
|
|
global $injector, $notification, $prefs, $registry;
|
|
|
|
/* The message text and headers. */
|
|
$expand = array();
|
|
$header = array(
|
|
'to' => '',
|
|
'cc' => '',
|
|
'bcc' => ''
|
|
);
|
|
$msg = '';
|
|
$this->title = _("Compose Message");
|
|
|
|
/* Get the list of headers to display. */
|
|
$display_hdrs = array(
|
|
'to' => _("To: "),
|
|
'cc' => _("Cc: "),
|
|
'bcc' => ("Bcc: ")
|
|
);
|
|
|
|
/* Set the current identity. */
|
|
$identity = $injector->getInstance('IMP_Identity');
|
|
if (!$prefs->isLocked('default_identity') &&
|
|
isset($this->vars->identity)) {
|
|
$identity->setDefault($this->vars->identity);
|
|
}
|
|
|
|
/* Determine if mailboxes are readonly. */
|
|
$drafts = IMP_Mailbox::getPref(IMP_Mailbox::MBOX_DRAFTS);
|
|
$readonly_drafts = $drafts && $drafts->readonly;
|
|
$sent_mail = $identity->getValue(IMP_Mailbox::MBOX_SENT);
|
|
$save_sent_mail = (!$sent_mail || $sent_mail->readonly)
|
|
? false
|
|
: $prefs->getValue('save_sent_mail');
|
|
|
|
/* Determine if compose mode is disabled. */
|
|
$compose_disable = !IMP_Compose::canCompose();
|
|
|
|
/* Initialize objects. */
|
|
$imp_compose = $injector->getInstance('IMP_Factory_Compose')->create($this->vars->composeCache);
|
|
|
|
/* Are attachments allowed? */
|
|
$attach_upload = $imp_compose->canUploadAttachment();
|
|
|
|
foreach (array_keys($display_hdrs) as $val) {
|
|
$header[$val] = $this->vars->$val;
|
|
|
|
/* If we are reloading the screen, check for expand matches. */
|
|
if ($this->vars->composeCache) {
|
|
$expanded = array();
|
|
for ($i = 0; $i < 5; ++$i) {
|
|
if ($tmp = $this->vars->get($val . '_expand_' . $i)) {
|
|
$expanded[] = $tmp;
|
|
}
|
|
}
|
|
if (!empty($expanded)) {
|
|
$header['to'] = strlen($header['to'])
|
|
? implode(', ', $expanded) . ', ' . $header['to']
|
|
: implode(', ', $expanded);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Add attachment. */
|
|
if ($attach_upload &&
|
|
isset($_FILES['upload_1']) &&
|
|
strlen($_FILES['upload_1']['name'])) {
|
|
try {
|
|
$atc_ob = $imp_compose->addAttachmentFromUpload('upload_1');
|
|
if ($atc_ob[0] instanceof IMP_Compose_Exception) {
|
|
throw $atc_ob[0];
|
|
}
|
|
if ($this->vars->a == _("Expand Names")) {
|
|
$notification->push(sprintf(_("Added \"%s\" as an attachment."), $atc_ob[0]->getPart()->getName()), 'horde.success');
|
|
}
|
|
} catch (IMP_Compose_Exception $e) {
|
|
$this->vars->a = null;
|
|
$notification->push($e, 'horde.error');
|
|
}
|
|
}
|
|
|
|
/* Run through the action handlers. */
|
|
switch ($this->vars->a) {
|
|
// 'd' = draft
|
|
// 'en' = edit as new
|
|
// 't' = template
|
|
case 'd':
|
|
case 'en':
|
|
case 't':
|
|
try {
|
|
switch ($this->vars->a) {
|
|
case 'd':
|
|
$result = $imp_compose->resumeDraft($this->indices, array(
|
|
'format' => 'text'
|
|
));
|
|
$this->view->resume = true;
|
|
break;
|
|
|
|
case 'en':
|
|
$result = $imp_compose->editAsNew($this->indices, array(
|
|
'format' => 'text'
|
|
));
|
|
break;
|
|
|
|
case 't':
|
|
$result = $imp_compose->useTemplate($this->indices, array(
|
|
'format' => 'text'
|
|
));
|
|
break;
|
|
}
|
|
|
|
$msg = $result['body'];
|
|
$header = array_merge(
|
|
$header,
|
|
$this->_convertToHeader($result)
|
|
);
|
|
if (!is_null($result['identity']) &&
|
|
($result['identity'] != $identity->getDefault()) &&
|
|
!$prefs->isLocked('default_identity')) {
|
|
$identity->setDefault($result['identity']);
|
|
$sent_mail = $identity->getValue(IMP_Mailbox::MBOX_SENT);
|
|
}
|
|
} catch (IMP_Compose_Exception $e) {
|
|
$notification->push($e);
|
|
}
|
|
break;
|
|
|
|
case _("Expand Names"):
|
|
foreach (array_keys($display_hdrs) as $val) {
|
|
if (($val == 'to') || ($this->vars->action != 'rc')) {
|
|
$res = $this->_expandAddresses($header[$val]);
|
|
if (is_string($res)) {
|
|
$header[$val] = $res;
|
|
} else {
|
|
$header[$val] = $res[0];
|
|
$expand[$val] = array_slice($res, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isset($this->vars->action)) {
|
|
$this->vars->a = $this->vars->action;
|
|
}
|
|
break;
|
|
|
|
// 'r' = reply
|
|
// 'rl' = reply to list
|
|
// 'ra' = reply to all
|
|
case 'r':
|
|
case 'ra':
|
|
case 'rl':
|
|
$actions = array(
|
|
'r' => IMP_Compose::REPLY_SENDER,
|
|
'ra' => IMP_Compose::REPLY_ALL,
|
|
'rl' => IMP_Compose::REPLY_LIST
|
|
);
|
|
|
|
try {
|
|
$reply_msg = $imp_compose->replyMessage(
|
|
$actions[$this->vars->a],
|
|
$this->_getContents(),
|
|
array(
|
|
'format' => 'text',
|
|
'to' => $header['to']
|
|
)
|
|
);
|
|
} catch (IMP_Exception $e) {
|
|
$notification->push($e, 'horde.error');
|
|
break;
|
|
}
|
|
|
|
$header = $this->_convertToHeader($reply_msg);
|
|
|
|
$notification->push(_("Reply text will be automatically appended to your outgoing message."), 'horde.message');
|
|
$this->title = _("Reply");
|
|
break;
|
|
|
|
// 'f' = forward
|
|
case 'f':
|
|
try {
|
|
$fwd_msg = $imp_compose->forwardMessage(
|
|
IMP_Compose::FORWARD_ATTACH,
|
|
$this->_getContents(),
|
|
false
|
|
);
|
|
} catch (IMP_Exception $e) {
|
|
$notification->push($e, 'horde.error');
|
|
break;
|
|
}
|
|
|
|
$header = $this->_convertToHeader($fwd_msg);
|
|
|
|
$notification->push(_("Forwarded message will be automatically added to your outgoing message."), 'horde.message');
|
|
$this->title = _("Forward");
|
|
break;
|
|
|
|
// 'rc' = redirect compose
|
|
case 'rc':
|
|
$imp_compose->redirectMessage($this->indices);
|
|
$this->title = _("Redirect");
|
|
break;
|
|
|
|
case _("Redirect"):
|
|
try {
|
|
$num_msgs = $imp_compose->sendRedirectMessage($header['to']);
|
|
$imp_compose->destroy('send');
|
|
|
|
$notification->push(ngettext("Message redirected successfully.", "Messages redirected successfully.", count($num_msgs)), 'horde.success');
|
|
IMP_Minimal_Mailbox::url(array('mailbox' => $this->indices->mailbox))->redirect();
|
|
} catch (Horde_Exception $e) {
|
|
$this->vars->a = 'rc';
|
|
$notification->push($e);
|
|
}
|
|
break;
|
|
|
|
case _("Save Draft"):
|
|
case _("Send"):
|
|
switch ($this->vars->a) {
|
|
case _("Save Draft"):
|
|
if ($readonly_drafts) {
|
|
break 2;
|
|
}
|
|
break;
|
|
|
|
case _("Send"):
|
|
if ($compose_disable) {
|
|
break 2;
|
|
}
|
|
break;
|
|
}
|
|
|
|
$message = strval($this->vars->message);
|
|
$f_to = $header['to'];
|
|
$old_header = $header;
|
|
$header = array();
|
|
|
|
switch ($imp_compose->replyType(true)) {
|
|
case IMP_Compose::REPLY:
|
|
try {
|
|
$reply_msg = $imp_compose->replyMessage(IMP_Compose::REPLY_SENDER, $imp_compose->getContentsOb(), array(
|
|
'to' => $f_to
|
|
));
|
|
$msg = $reply_msg['body'];
|
|
} catch (IMP_Exception $e) {
|
|
$notification->push($e, 'horde.error');
|
|
$msg = '';
|
|
}
|
|
$message .= "\n" . $msg;
|
|
break;
|
|
|
|
case IMP_Compose::FORWARD:
|
|
try {
|
|
$fwd_msg = $imp_compose->forwardMessage(IMP_Compose::FORWARD_ATTACH, $imp_compose->getContentsOb());
|
|
$msg = $fwd_msg['body'];
|
|
} catch (IMP_Exception $e) {
|
|
$notification->push($e, 'horde.error');
|
|
}
|
|
$message .= "\n" . $msg;
|
|
break;
|
|
}
|
|
|
|
try {
|
|
$header['from'] = strval($identity->getFromLine(null, $this->vars->from));
|
|
} catch (Horde_Exception $e) {
|
|
$header['from'] = '';
|
|
}
|
|
$header['replyto'] = $identity->getValue('replyto_addr');
|
|
$header['subject'] = strval($this->vars->subject);
|
|
|
|
foreach (array_keys($display_hdrs) as $val) {
|
|
$header[$val] = $old_header[$val];
|
|
}
|
|
|
|
switch ($this->vars->a) {
|
|
case _("Save Draft"):
|
|
try {
|
|
$notification->push($imp_compose->saveDraft($header, $message), 'horde.success');
|
|
if ($prefs->getValue('close_draft')) {
|
|
$imp_compose->destroy('save_draft');
|
|
IMP_Minimal_Mailbox::url(array('mailbox' => $this->indices->mailbox))->redirect();
|
|
}
|
|
} catch (IMP_Compose_Exception $e) {
|
|
$notification->push($e);
|
|
}
|
|
break;
|
|
|
|
case _("Send"):
|
|
try {
|
|
$imp_compose->buildAndSendMessage(
|
|
$message,
|
|
$header,
|
|
$identity,
|
|
array(
|
|
'readreceipt' => ($prefs->getValue('request_mdn') == 'always'),
|
|
'save_sent' => $save_sent_mail,
|
|
'sent_mail' => $sent_mail
|
|
)
|
|
);
|
|
$imp_compose->destroy('send');
|
|
|
|
$notification->push(_("Message sent successfully."), 'horde.success');
|
|
IMP_Minimal_Mailbox::url(array('mailbox' => $this->indices->mailbox))->redirect();
|
|
} catch (IMP_Compose_Exception $e) {
|
|
$notification->push($e);
|
|
|
|
/* Switch to tied identity. */
|
|
if (!is_null($e->tied_identity)) {
|
|
$identity->setDefault($e->tied_identity);
|
|
$notification->push(_("Your identity has been switched to the identity associated with the current recipient address. The identity will not be checked again during this compose action."));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case _("Cancel"):
|
|
$imp_compose->destroy('cancel');
|
|
IMP_Minimal_Mailbox::url(array('mailbox' => $this->indices->mailbox))->redirect();
|
|
exit;
|
|
|
|
case _("Discard Draft"):
|
|
$imp_compose->destroy('discard');
|
|
IMP_Minimal_Mailbox::url(array('mailbox' => $this->indices->mailbox))->redirect();
|
|
exit;
|
|
}
|
|
|
|
/* Grab any data that we were supplied with. */
|
|
if (empty($msg)) {
|
|
$msg = strval($this->vars->message);
|
|
}
|
|
if (empty($header['subject'])) {
|
|
$header['subject'] = strval($this->vars->subject);
|
|
}
|
|
|
|
$this->view->cacheid = $imp_compose->getCacheId();
|
|
$this->view->hmac = $imp_compose->getHmac();
|
|
$this->view->menu = $this->getMenu('compose');
|
|
$this->view->url = self::url();
|
|
$this->view->user = $registry->getAuth();
|
|
|
|
switch ($this->vars->a) {
|
|
case 'rc':
|
|
$this->_pages[] = 'redirect';
|
|
$this->_pages[] = 'menu';
|
|
unset($display_hdrs['cc'], $display_hdrs['bcc']);
|
|
break;
|
|
|
|
default:
|
|
$this->_pages[] = 'compose';
|
|
$this->_pages[] = 'menu';
|
|
|
|
$this->view->compose_enable = !$compose_disable;
|
|
$this->view->msg = $msg;
|
|
$this->view->save_draft = ($injector->getInstance('IMP_Factory_Imap')->create()->access(IMP_Imap::ACCESS_DRAFTS) && !$readonly_drafts);
|
|
$this->view->subject = $header['subject'];
|
|
|
|
$select_list = $identity->getSelectList();
|
|
$default_identity = $identity->getDefault();
|
|
|
|
if ($prefs->isLocked('default_identity')) {
|
|
$select_list = array(
|
|
$default_identity => $select_list[$default_identity]
|
|
);
|
|
}
|
|
|
|
$tmp = array();
|
|
foreach ($select_list as $key => $val) {
|
|
$tmp[] = array(
|
|
'key' => $key,
|
|
'sel' => ($key == $default_identity),
|
|
'val' => $val
|
|
);
|
|
}
|
|
$this->view->identities = $tmp;
|
|
|
|
if ($attach_upload) {
|
|
$this->view->attach = true;
|
|
if (count($imp_compose)) {
|
|
$imp_compose->getIterator()->rewind();
|
|
$atc_part = $imp_compose->getIterator()->current()->getPart();
|
|
$this->view->attach_name = $atc_part->getName();
|
|
$this->view->attach_size = IMP::sizeFormat($atc_part->getBytes());
|
|
$this->view->attach_type = $atc_part->getType();
|
|
}
|
|
}
|
|
|
|
$this->title = _("Message Composition");
|
|
}
|
|
|
|
$hdrs = array();
|
|
foreach ($display_hdrs as $key => $val) {
|
|
$tmp = array(
|
|
'key' => $key,
|
|
'label' => $val,
|
|
'val' => $header[$key]
|
|
);
|
|
|
|
if (isset($expand[$key])) {
|
|
$tmp['matchlabel'] = (count($expand[$key][1]) > 5)
|
|
? sprintf(_("Ambiguous matches for \"%s\" (first 5 matches displayed):"), $expand[$key][0])
|
|
: sprintf(_("Ambiguous matches for \"%s\":"), $expand[$key][0]);
|
|
|
|
$tmp['match'] = array();
|
|
foreach ($expand[$key][1] as $key2 => $val2) {
|
|
if ($key2 == 5) {
|
|
break;
|
|
}
|
|
$tmp['match'][] = array(
|
|
'id' => $key . '_expand_' . $key2,
|
|
'val' => $val2
|
|
);
|
|
}
|
|
}
|
|
|
|
$hdrs[] = $tmp;
|
|
}
|
|
|
|
$this->view->hdrs = $hdrs;
|
|
$this->view->title = $this->title;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static public function url(array $opts = array())
|
|
{
|
|
return Horde::url('minimal.php')->add('page', 'compose')->unique();
|
|
}
|
|
|
|
/**
|
|
* Expand addresses in a string. Only the last address in the string will
|
|
* be expanded.
|
|
*
|
|
* @param string $input The input string.
|
|
*
|
|
* @return mixed If a string, this value should be used as the new
|
|
* input string. If an array, the first value is the
|
|
* input string without the search string; the second
|
|
* value is the search string; and the third value is
|
|
* the list of matching addresses.
|
|
*/
|
|
protected function _expandAddresses($input)
|
|
{
|
|
$addr_list = IMP::parseAddressList($input, array(
|
|
'default_domain' => null
|
|
));
|
|
|
|
if (!($size = count($addr_list))) {
|
|
return '';
|
|
}
|
|
|
|
$search = $addr_list[$size - 1];
|
|
|
|
/* Don't search if the search string looks like an e-mail address. */
|
|
if (!is_null($search->mailbox) && !is_null($search->host)) {
|
|
return strval($search);
|
|
}
|
|
|
|
/* "Search" string will be in mailbox element. */
|
|
$imple = new IMP_Ajax_Imple_ContactAutoCompleter();
|
|
$res = $imple->getAddressList($search->mailbox);
|
|
|
|
switch (count($res)) {
|
|
case 0:
|
|
$GLOBALS['notification']->push(sprintf(_("Search for \"%s\" failed: no address found."), $search->mailbox), 'horde.warning');
|
|
return strval($addr_list);
|
|
case 1:
|
|
$addr_list[$size] = $res[0];
|
|
return strval($addr_list);
|
|
|
|
default:
|
|
$GLOBALS['notification']->push(_("Ambiguous address found."), 'horde.warning');
|
|
unset($addr_list[$size]);
|
|
return array(
|
|
strval($addr_list),
|
|
$search->mailbox,
|
|
$res
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create the IMP_Contents objects needed to create a message.
|
|
*
|
|
* @param Horde_Variables $vars The variables object.
|
|
*
|
|
* @return IMP_Contents The IMP_Contents object.
|
|
* @throws IMP_Exception
|
|
*/
|
|
protected function _getContents()
|
|
{
|
|
try {
|
|
return $GLOBALS['injector']->getInstance('IMP_Factory_Contents')->create($this->indices);
|
|
} catch (Horde_Exception $e) {}
|
|
|
|
$this->vars->buid = null;
|
|
$this->vars->type = 'new';
|
|
|
|
throw new IMP_Exception(_("Could not retrieve message data from the mail server."));
|
|
}
|
|
|
|
/**
|
|
* Convert a compose response object to header values.
|
|
*
|
|
* @param array $in Compose response object.
|
|
*
|
|
* @return array Header entry.
|
|
*/
|
|
protected function _convertToHeader($in)
|
|
{
|
|
$out = array();
|
|
|
|
if (isset($in['addr'])) {
|
|
$out['to'] = strval($in['addr']['to']);
|
|
$out['cc'] = strval($in['addr']['cc']);
|
|
$out['bcc'] = strval($in['addr']['bcc']);
|
|
}
|
|
|
|
if (isset($in['subject'])) {
|
|
$out['subject'] = $in['subject'];
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
}
|