public function replyMessage($type, $contents, array $opts = array())
{
global $injector, $language, $prefs;
if (!$contents instanceof IMP_Contents) {
throw new IMP_Exception(_("Could not retrieve message data from the mail server."));
}
$alist = new Horde_Mail_Rfc822_List();
$addr = array('to' => clone $alist, 'cc' => clone $alist, 'bcc' => clone $alist);
$h = $contents->getHeader();
$match_identity = $this->_getMatchingIdentity($h);
$reply_type = self::REPLY_SENDER;
if (!$this->_replytype) {
$this->_setMetadata('indices', $contents->getIndicesOb());
/* Set the Message-ID related headers (RFC 5322 [3.6.4]). */
if ($tmp = $h['Message-ID']) {
$msg_id = $tmp->getIdentificationOb();
$msg_id = reset($msg_id->ids);
if (strlen($msg_id)) {
$this->_setMetadata('in_reply_to', $msg_id);
}
} else {
$msg_id = null;
}
if ($tmp = $h['References']) {
$ref_ob = $tmp->getIdentificationOb();
if (!count($ref_ob->ids) && ($tmp = $h['In-Reply-To'])) {
$ref_ob = $tmp->getIdentificationOb();
if (count($ref_ob->ids) > 1) {
$ref_ob->ids = array();
}
}
if (count($ref_ob->ids)) {
$this->_setMetadata('references', array_merge($ref_ob->ids, array_filter(array($msg_id))));
}
}
}
$subject = strlen($s = $h['Subject']) ? 'Re: ' . strval(new Horde_Imap_Client_Data_BaseSubject($s, array('keepblob' => true))) : 'Re: ';
$force = false;
if (in_array($type, array(self::REPLY_AUTO, self::REPLY_SENDER))) {
if (isset($opts['to'])) {
$addr['to']->add($opts['to']);
$force = true;
} elseif ($tmp = $h['reply-to']) {
$addr['to']->add($tmp->getAddressList());
$force = true;
} elseif ($tmp = $h['from']) {
$addr['to']->add($tmp->getAddressList());
}
} elseif ($type === self::REPLY_ALL) {
$force = isset($h['reply-to']);
}
/* We might need $list_info in the reply_all section. */
$list_info = in_array($type, array(self::REPLY_AUTO, self::REPLY_LIST)) ? $contents->getListInformation() : null;
if (!is_null($list_info) && !empty($list_info['reply_list'])) {
/* If To/Reply-To and List-Reply address are the same, no need
* to handle these address separately. */
$rlist = new Horde_Mail_Rfc822_Address($list_info['reply_list']);
if (!$rlist->match($addr['to'])) {
$addr['to'] = clone $alist;
$addr['to']->add($rlist);
$reply_type = self::REPLY_LIST;
}
} elseif (in_array($type, array(self::REPLY_ALL, self::REPLY_AUTO))) {
/* Clear the To field if we are auto-determining addresses. */
if ($type == self::REPLY_AUTO) {
$addr['to'] = clone $alist;
}
/* Filter out our own address from the addresses we reply to. */
$identity = $injector->getInstance('IMP_Identity');
$all_addrs = $identity->getAllFromAddresses();
/* Build the To: header. It is either:
* 1) the Reply-To address (if not a personal address)
* 2) the From address(es) (if it doesn't contain a personal
* address)
* 3) all remaining Cc addresses. */
$to_fields = array('from', 'reply-to');
foreach (array('reply-to', 'from', 'to', 'cc') as $val) {
/* If either a reply-to or $to is present, we use this address
* INSTEAD of the from address. */
if ($force && $val == 'from' || !($tmp = $h[$val])) {
continue;
}
$ob = $tmp->getAddressList(true);
/* For From: need to check if at least one of the addresses is
* personal. */
if ($val == 'from') {
foreach ($ob->raw_addresses as $addr_ob) {
if ($all_addrs->contains($addr_ob)) {
/* The from field contained a personal address.
* Use the 'To' header as the primary reply-to
* address instead. */
$to_fields[] = 'to';
/* Add other non-personal from addresses to the
* list of CC addresses. */
$ob->setIteratorFilter($ob::BASE_ELEMENTS, $all_addrs);
$addr['cc']->add($ob);
$all_addrs->add($ob);
continue 2;
}
}
}
$ob->setIteratorFilter($ob::BASE_ELEMENTS, $all_addrs);
foreach ($ob as $hdr_ob) {
if ($hdr_ob instanceof Horde_Mail_Rfc822_Group) {
$addr['cc']->add($hdr_ob);
$all_addrs->add($hdr_ob->addresses);
} elseif ($val != 'to' || is_null($list_info) || !$force || empty($list_info['exists'])) {
/* Don't add as To address if this is a list that
* doesn't have a post address but does have a
* reply-to address. */
if (in_array($val, $to_fields)) {
/* If from/reply-to doesn't have personal
* information, check from address. */
if (is_null($hdr_ob->personal) && ($tmp = $h['from']) && ($to_ob = $tmp->getAddressList(true)->first()) && !is_null($to_ob->personal) && $hdr_ob->match($to_ob)) {
$addr['to']->add($to_ob);
} else {
$addr['to']->add($hdr_ob);
}
} else {
$addr['cc']->add($hdr_ob);
}
$all_addrs->add($hdr_ob);
}
}
}
/* Build the Cc: (or possibly the To:) header. If this is a
* reply to a message that was already replied to by the user,
* this reply will go to the original recipients (Request
* #8485). */
if (count($addr['cc'])) {
$reply_type = self::REPLY_ALL;
}
if (!count($addr['to'])) {
$addr['to'] = $addr['cc'];
$addr['cc'] = clone $alist;
}
/* Build the Bcc: header. */
if ($tmp = $h['bcc']) {
$bcc = $tmp->getAddressList(true);
$bcc->add($identity->getBccAddresses());
$bcc->setIteratorFilter(0, $all_addrs);
foreach ($bcc as $val) {
$addr['bcc']->add($val);
}
}
}
if (!$this->_replytype || $reply_type != $this->_replytype) {
$this->_replytype = $reply_type;
$this->changed = 'changed';
}
$ret = $this->replyMessageText($contents, array('format' => isset($opts['format']) ? $opts['format'] : null));
if ($prefs->getValue('reply_charset') && $ret['charset'] != $this->charset) {
$this->charset = $ret['charset'];
$this->changed = 'changed';
}
unset($ret['charset']);
if ($type == self::REPLY_AUTO) {
switch ($reply_type) {
case self::REPLY_ALL:
try {
$recip_list = $this->recipientList($addr);
$ret['reply_recip'] = count($recip_list['list']);
} catch (IMP_Compose_Exception $e) {
$ret['reply_recip'] = 0;
}
break;
case self::REPLY_LIST:
if (($list_parse = $injector->getInstance('Horde_ListHeaders')->parse('list-id', strval($h['List-Id']))) && !is_null($list_parse->label)) {
$ret['reply_list_id'] = $list_parse->label;
}
break;
}
}
if (($lang = $h['Accept-Language']) || ($lang = $h['X-Accept-Language'])) {
$langs = array();
foreach (explode(',', $lang->value_single) as $val) {
if (($name = Horde_Nls::getLanguageISO($val)) !== null) {
$langs[trim($val)] = $name;
}
}
$ret['lang'] = array_unique($langs);
/* Don't show display if original recipient is asking for reply in
* the user's native language. */
if (count($ret['lang']) == 1 && reset($ret['lang']) && substr(key($ret['lang']), 0, 2) == substr($language, 0, 2)) {
unset($ret['lang']);
}
}
return array_merge(array('addr' => $addr, 'identity' => $match_identity, 'subject' => $subject, 'type' => $reply_type), $ret);
}