/** * @see showInlineImage */ protected function _showInlineImage(IMP_Contents $contents) { global $injector, $prefs; if ($this->alwaysShow || !$prefs->getValue('image_replacement')) { return true; } if (!$contents || !($tmp = $contents->getHeader()->getHeader('from')) || !($from = $tmp->getAddressList(true))) { return false; } $res = $injector->getInstance('IMP_Contacts')->searchEmail($from->first()->bare_address, array('email_exact' => true)); if (count($res)) { /* Don't allow personal addresses by default - this is the only * e-mail address a Spam sender for sure knows you will recognize * so it is too much of a loophole. */ $res->setIteratorFilter(0, $injector->getInstance('IMP_Identity')->getAllFromAddresses()); foreach ($from as $val) { if ($res->contains($val)) { return true; } } } /* Check safe address list. */ $safeAddrs = $injector->getInstance('IMP_Prefs_Special_ImageReplacement')->safeAddrList(); foreach ($from as $val) { if ($safeAddrs->contains($val)) { return true; } } return false; }
/** */ public function report(IMP_Contents $contents, $action) { global $injector, $registry; $imp_compose = $injector->getInstance('IMP_Factory_Compose')->create(); switch ($this->_format) { case 'redirect': /* Send the message. */ try { $imp_compose->redirectMessage($contents->getIndicesOb()); $imp_compose->sendRedirectMessage($this->_email, false); return true; } catch (IMP_Compose_Exception $e) { $e->log(); } break; case 'digest': default: try { $from_line = $injector->getInstance('IMP_Identity')->getFromLine(); } catch (Horde_Exception $e) { $from_line = null; } /* Build the MIME structure. */ $mime = new Horde_Mime_Part(); $mime->setType('multipart/digest'); $rfc822 = new Horde_Mime_Part(); $rfc822->setType('message/rfc822'); $rfc822->setContents($contents->fullMessageText(array('stream' => true))); $mime->addPart($rfc822); $spam_headers = new Horde_Mime_Headers(); $spam_headers->addMessageIdHeader(); $spam_headers->addHeader('Date', date('r')); $spam_headers->addHeader('To', $this->_email); if (!is_null($from_line)) { $spam_headers->addHeader('From', $from_line); } $spam_headers->addHeader('Subject', sprintf(_("%s report from %s"), $action == IMP_Spam::SPAM ? 'spam' : 'innocent', $registry->getAuth())); /* Send the message. */ try { $recip_list = $imp_compose->recipientList(array('to' => $this->_email)); $imp_compose->sendMessage($recip_list['list'], $spam_headers, $mime, 'UTF-8'); $rfc822->clearContents(); return true; } catch (IMP_Compose_Exception $e) { $e->log(); $rfc822->clearContents(); } break; } return false; }
/** * @throws IMP_Exception */ public function composeAttachPreview($id, $autodetect = false, $ctype = null) { if (!($atc = $this->_compose[$id]) || !($mime = $atc->getPart(true))) { $e = new IMP_Exception(_("Could not display attachment data.")); $e->logged = true; throw $e; } $mime->setMimeId($id); $contents = new IMP_Contents($mime); $render = $contents->renderMIMEPart($id, $contents::RENDER_RAW_FALLBACK, array('autodetect' => $autodetect, 'type' => $ctype)); if (!empty($render)) { return reset($render); } elseif ($autodetect) { $e = new IMP_Exception(_("Could not display attachment data.")); $e->logged = true; throw $e; } return array(); }
/** * Get a MIME Part for use in creating download. * * @param string $id MIME ID. * * @return Horde_Mime_Part MIME part. */ protected function _getRawDownloadPart($id) { $mime = $this->_contents->getMIMEPart($id); if ($this->_contents->canDisplay($id, IMP_Contents::RENDER_RAW)) { $render = $this->_contents->renderMIMEPart($id, IMP_Contents::RENDER_RAW); $part = reset($render); $mime->setContents($part['data'], array('encoding' => 'binary')); } return $mime; }
/** * Get a MIME Part for use in creating download. * * @param string $id MIME ID. * * @return Horde_Mime_Part MIME part, or null on error. */ protected function _getRawDownloadPart($id) { if (!($mime = $this->_contents->getMimePart($id))) { return null; } if ($this->_contents->canDisplay($id, IMP_Contents::RENDER_RAW)) { $render = $this->_contents->renderMIMEPart($id, IMP_Contents::RENDER_RAW); $part = reset($render); $mime->setContents($part['data'], array('encoding' => 'binary', 'usestream' => true)); } return $mime; }
/** */ public function report(IMP_Contents $contents, $action) { /* Use a pipe to write the message contents. This should be * secure. */ $proc = proc_open($this->_binary, array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes); if (!is_resource($proc)) { Horde::log(sprintf('Cannot open spam reporting program: %s', $proc), 'ERR'); return false; } stream_copy_to_stream($contents->fullMessageText(array('stream' => true)), $pipes[0]); fclose($pipes[0]); $stderr = ''; while (!feof($pipes[2])) { $stderr .= fgets($pipes[2]); } fclose($pipes[2]); if (!empty($stderr)) { Horde::log(sprintf('Error reporting spam: %s', $stderr), 'ERR'); } proc_close($proc); return true; }
/** * @see showInlineImage */ protected function _showInlineImage(IMP_Contents $contents) { global $injector, $prefs, $registry; if ($this->alwaysShow || !$prefs->getValue('image_replacement')) { return true; } if (!$contents || !($from = $contents->getHeader()->getOb('from'))) { return false; } if ($registry->hasMethod('contacts/search')) { $sparams = $injector->getInstance('IMP_Contacts')->getAddressbookSearchParams(); try { $res = $registry->call('contacts/search', array($from->bare_addresses, array('customStrict' => array('email'), 'fields' => array_fill_keys($sparams['sources'], array('email')), 'returnFields' => array('email'), 'rfc822Return' => true, 'sources' => $sparams['sources']))); // Don't allow personal addresses by default - this is the // only e-mail address a Spam sender for sure knows you will // recognize so it is too much of a loophole. $res->setIteratorFilter(0, $injector->getInstance('IMP_Identity')->getAllFromAddresses()); foreach ($from as $val) { if ($res->contains($val)) { return true; } } } catch (Horde_Exception $e) { // Ignore errors from the search - default to not showing // images. Horde::log($e, 'INFO'); } } /* Check safe address list. */ $safeAddrs = $injector->getInstance('IMP_Prefs_Special_ImageReplacement')->safeAddrList(); foreach ($from as $val) { if ($safeAddrs->contains($val)) { return true; } } return false; }
/** * Generate inline message display. * * @param array $options Options: * - mask: (integer) The mask needed for a getSummary() call. * - mimeid: (string) Restrict output to this MIME ID (and children). * * @return array See getInlineOutput(). */ protected function _getInlineOutput(array $options) { global $prefs, $registry; $atc_parts = $display_ids = $i = $metadata = $msgtext = $wrap_ids = array(); $text_out = ''; $view = $registry->getView(); $contents_mask = isset($options['mask']) ? $options['mask'] : 0; $mimeid_filter = isset($options['mimeid']) ? new Horde_Mime_Id($options['mimeid']) : null; $show_parts = $prefs->getValue('parts_display'); foreach ($this->contents->getMIMEMessage()->partIterator() as $part) { $mime_id = $part->getMimeId(); $i[] = $mime_id; if (isset($display_ids[$mime_id]) || isset($atc_parts[$mime_id])) { continue; } if ($mimeid_filter && (strval($mimeid_filter) != $mime_id && !$mimeid_filter->isChild($mime_id))) { continue; } if (!($render_mode = $this->contents->canDisplay($mime_id, IMP_Contents::RENDER_INLINE_AUTO))) { if (IMP_Mime_Attachment::isAttachment($part)) { if ($show_parts == 'atc') { $atc_parts[$mime_id] = 1; } if ($contents_mask) { $msgtext[$mime_id] = array('text' => $this->_formatSummary($this->contents->getSummary($mime_id, $contents_mask), true)); } } continue; } $render_part = $this->contents->renderMIMEPart($mime_id, $render_mode); if ($show_parts == 'atc' && IMP_Mime_Attachment::isAttachment($part) && (empty($render_part) || !($render_mode & IMP_Contents::RENDER_INLINE))) { $atc_parts[$mime_id] = 1; } if (empty($render_part)) { if ($contents_mask && IMP_Mime_Attachment::isAttachment($part)) { $msgtext[$mime_id] = array('text' => $this->_formatSummary($this->contents->getSummary($mime_id, $contents_mask), true)); } continue; } reset($render_part); while (list($id, $info) = each($render_part)) { $display_ids[$id] = 1; if (empty($info)) { continue; } $part_text = $contents_mask && empty($info['nosummary']) ? $this->_formatSummary($this->contents->getSummary($id, $contents_mask), !empty($info['attach'])) : ''; if (empty($info['attach'])) { if (isset($info['status'])) { if (!is_array($info['status'])) { $info['status'] = array($info['status']); } $render_issues = array(); foreach ($info['status'] as $val) { if (in_array($view, $val->views)) { if ($val instanceof IMP_Mime_Status_RenderIssue) { $render_issues[] = $val; } else { $part_text .= strval($val); } } } if (!empty($render_issues)) { $render_issues_ob = new IMP_Mime_Status_RenderIssue_Display(); $render_issues_ob->addIssues($render_issues); $part_text .= strval($render_issues_ob); } } $part_text .= '<div class="mimePartData">' . $info['data'] . '</div>'; } elseif ($show_parts == 'atc') { $atc_parts[$id] = 1; } $msgtext[$id] = array('text' => $part_text, 'wrap' => empty($info['wrap']) ? null : $info['wrap']); if (isset($info['metadata'])) { /* Format: array(identifier, ...[data]...) */ $metadata = array_merge($metadata, $info['metadata']); } } } if (!empty($msgtext)) { uksort($msgtext, 'strnatcmp'); } reset($msgtext); while (list($id, $part) = each($msgtext)) { while (!empty($wrap_ids)) { $id_ob = new Horde_Mime_Id(end($wrap_ids)); if ($id_ob->isChild($id)) { break; } array_pop($wrap_ids); $text_out .= '</div>'; } if (!empty($part['wrap'])) { $text_out .= '<div class="' . $part['wrap'] . '" impcontentsmimeid="' . $id . '">'; $wrap_ids[] = $id; } $text_out .= '<div class="mimePartBase"' . (empty($part['wrap']) ? ' impcontentsmimeid="' . $id . '"' : '') . '>' . $part['text'] . '</div>'; } $text_out .= str_repeat('</div>', count($wrap_ids)); if (!strlen($text_out)) { $text_out = strval(new IMP_Mime_Status(null, _("There are no parts that can be shown inline."))); } $atc_parts = $show_parts == 'all' ? $i : array_keys($atc_parts); return array('atc_parts' => $atc_parts, 'display_ids' => array_keys($display_ids), 'metadata' => $metadata, 'msgtext' => $text_out, 'one_part' => count($i) === 1); }
/** * Regenerates body text for use in the compose screen from IMAP data. * * @param IMP_Contents $contents An IMP_Contents object. * @param array $options Additional options: * <ul> * <li>html: (boolean) Return text/html part, if available.</li> * <li>imp_msg: (integer) If non-empty, the message data was created by * IMP. Either: * <ul> * <li>self::COMPOSE</li> * <li>self::FORWARD</li> * <li>self::REPLY</li> * </ul> * </li> * <li>replylimit: (boolean) Enforce length limits?</li> * <li>toflowed: (boolean) Do flowed conversion?</li> * </ul> * * @return mixed Null if bodypart not found, or array with the following * keys: * - charset: (string) The guessed charset to use. * - flowed: (Horde_Text_Flowed) A flowed object, if the text is flowed. * Otherwise, null. * - id: (string) The MIME ID of the bodypart. * - mode: (string) Either 'text' or 'html'. * - text: (string) The body text. */ protected function _getMessageText($contents, array $options = array()) { global $conf, $injector, $notification, $prefs; $body_id = null; $mode = 'text'; $options = array_merge(array('imp_msg' => self::COMPOSE), $options); if (!empty($options['html']) && self::canHtmlCompose() && ($body_id = $contents->findBody('html')) !== null) { $mime_message = $contents->getMIMEMessage(); switch ($mime_message->getPrimaryType()) { case 'multipart': if ($body_id != '1' && $mime_message->getSubType() == 'mixed' && ($id_ob = new Horde_Mime_Id('1')) && !$id_ob->isChild($body_id)) { $body_id = null; } else { $mode = 'html'; } break; default: if (strval($body_id) != '1') { $body_id = null; } else { $mode = 'html'; } break; } } if (is_null($body_id)) { $body_id = $contents->findBody(); if (is_null($body_id)) { return null; } } if (!($part = $contents->getMimePart($body_id))) { return null; } $type = $part->getType(); $part_charset = $part->getCharset(); $msg = Horde_String::convertCharset($part->getContents(), $part_charset, 'UTF-8'); /* Enforce reply limits. */ if (!empty($options['replylimit']) && !empty($conf['compose']['reply_limit'])) { $limit = $conf['compose']['reply_limit']; if (Horde_String::length($msg) > $limit) { $msg = Horde_String::substr($msg, 0, $limit) . "\n" . _("[Truncated Text]"); } } if ($mode == 'html') { $dom = $injector->getInstance('Horde_Core_Factory_TextFilter')->filter($msg, 'Xss', array('charset' => $this->charset, 'return_dom' => true, 'strip_style_attributes' => false)); /* If we are replying to a related part, and this part refers * to local message parts, we need to move those parts into this * message (since the original message may disappear during the * compose process). */ if ($related_part = $contents->findMimeType($body_id, 'multipart/related')) { $this->_setMetadata('related_contents', $contents); $related_ob = new Horde_Mime_Related($related_part); $related_ob->cidReplace($dom, array($this, '_getMessageTextCallback'), $part_charset); $this->_setMetadata('related_contents', null); } /* Convert any Data URLs to attachments. */ $xpath = new DOMXPath($dom->dom); foreach ($xpath->query('//*[@src]') as $val) { $data_url = new Horde_Url_Data($val->getAttribute('src')); if (strlen($data_url->data)) { $data_part = new Horde_Mime_Part(); $data_part->setContents($data_url->data); $data_part->setType($data_url->type); try { $atc = $this->addAttachmentFromPart($data_part); $val->setAttribute('src', $atc->viewUrl()); $this->addRelatedAttachment($atc, $val, 'src'); } catch (IMP_Compose_Exception $e) { $notification->push($e, 'horde.warning'); } } } $msg = $dom->returnBody(); } elseif ($type == 'text/html') { $msg = $injector->getInstance('Horde_Core_Factory_TextFilter')->filter($msg, 'Html2text'); $type = 'text/plain'; } /* Always remove leading/trailing whitespace. The data in the * message body is not intended to be the exact representation of the * original message (use forward as message/rfc822 part for that). */ $msg = trim($msg); if ($type == 'text/plain') { if ($prefs->getValue('reply_strip_sig') && ($pos = strrpos($msg, "\n-- ")) !== false) { $msg = rtrim(substr($msg, 0, $pos)); } /* Remove PGP armored text. */ $pgp = $injector->getInstance('Horde_Crypt_Pgp_Parse')->parseToPart($msg); if (!is_null($pgp)) { $msg = ''; $pgp->buildMimeIds(); foreach ($pgp->partIterator() as $val) { if ($val->getPrimaryType() === 'text') { $msg .= $val->getContents(); } } } if ($part->getContentTypeParameter('format') == 'flowed') { $flowed = new Horde_Text_Flowed($msg, 'UTF-8'); if (Horde_String::lower($part->getContentTypeParameter('delsp')) == 'yes') { $flowed->setDelSp(true); } $flowed->setMaxLength(0); $msg = $flowed->toFixed(false); } else { /* If the input is *not* in flowed format, make sure there is * no padding at the end of lines. */ $msg = preg_replace("/\\s*\n/U", "\n", $msg); } if (isset($options['toflowed'])) { $flowed = new Horde_Text_Flowed($msg, 'UTF-8'); $msg = $options['toflowed'] ? $flowed->toFlowed(true) : $flowed->toFlowed(false, array('nowrap' => true)); } } if (strcasecmp($part->getCharset(), 'windows-1252') === 0) { $part_charset = 'ISO-8859-1'; } return array('charset' => $part_charset, 'flowed' => isset($flowed) ? $flowed : null, 'id' => $body_id, 'mode' => $mode, 'text' => $msg); }
/** * Create the object used to display the message. * * @param array $args Configuration parameters: * - headers: (array) The headers desired in the returned headers array * (only used with non-preview view). * - preview: (boolean) Is this the preview view? * * @return array Array with the following keys: * - atc_download: The download all link * - atc_label: The label to use for Attachments * - atc_list: The list (HTML code) of attachments * - bcc (FULL): The Bcc addresses * - cc: The CC addresses * - fulldate (FULL): The full canonical date. * - from: The From addresses * - headers (FULL): An array of headers (not including basic headers) * - js: Javascript code to run on display * - list_info (FULL): List information. * - localdate (PREVIEW): The date formatted to the user's timezone * - md: Metadata * - msgtext: The text of the message * - onepart: True if message only contains one part. * - replyTo (FULL): The Reply-to addresses * - save_as: The save link * - subject: The subject * - subjectlink: The subject with linked URLs/email addresses (defaults * to 'subject') * - title (FULL): The title of the page * - to: The To addresses * * @throws IMP_Exception */ public function showMessage($args) { global $injector, $page_output, $prefs, $registry, $session; $preview = !empty($args['preview']); $result = array(); $mime_headers = $this->_peek ? $this->_contents->getHeader() : $this->_contents->getHeaderAndMarkAsSeen(); $headers = array(); $imp_ui = $injector->getInstance('IMP_Message_Ui'); /* Develop the list of Headers to display now. Deal with the 'basic' * header information first since there are various manipulations * done to them. */ $basic_headers = $imp_ui->basicHeaders(); if (empty($args['headers'])) { $args['headers'] = array('from', 'date', 'to', 'cc', 'bcc'); } $headers_list = array_intersect_key($basic_headers, array_flip($args['headers'])); /* Build From/To/Cc/Bcc/Reply-To links. */ foreach (array('from', 'to', 'cc', 'bcc', 'reply-to') as $val) { if (isset($headers_list[$val]) && (!$preview || $val != 'reply-to')) { if ($tmp = $this->getAddressHeader($val)) { $result[$val] = $tmp; } if ($preview) { unset($headers_list[$val]); } } } /* Build the rest of the headers. */ foreach ($headers_list as $head => $str) { if ($val = $mime_headers->getValue($head)) { if ($head == 'date') { /* Add local time to date header. */ $date_ob = new IMP_Message_Date($this->_envelope->date); $val = htmlspecialchars($date_ob->format($date_ob::DATE_LOCAL)); if ($preview) { $result['localdate'] = $val; } else { $result['fulldate'] = $date_ob->format($date_ob::DATE_FORCE); } } elseif (!$preview) { $val = htmlspecialchars($val); } if (!$preview) { $headers[$head] = array('id' => Horde_String::ucfirst($head), 'name' => $str, 'value' => $val); } } } if (empty($result['reply-to']) || $result['from']['addr'][0]->b == $result['reply-to']['addr'][0]->b) { unset($result['reply-to'], $headers['reply-to']); } /* JS requires camelized name for reply-to. */ if (!$preview && isset($headers['reply-to'])) { $result['replyTo'] = $result['reply-to']; $headers['reply-to']['id'] = 'ReplyTo'; unset($result['reply-to']); } /* Maillog information. */ $ajax_queue = $injector->getInstance('IMP_Ajax_Queue'); $ajax_queue->maillog($this->_indices); if (!$preview) { /* Display the user-specified headers for the current identity. */ $user_hdrs = $imp_ui->getUserHeaders(); foreach ($user_hdrs as $user_hdr) { $user_val = $mime_headers->getValue($user_hdr); if (!empty($user_val)) { if (!is_array($user_val)) { $user_val = array($user_val); } foreach ($user_val as $val) { $headers[] = array('name' => $user_hdr, 'value' => htmlspecialchars($val)); } } } $result['headers'] = array_values($headers); } /* Process the subject. */ $subject = $mime_headers->getValue('subject'); if ($subject) { $text_filter = $injector->getInstance('Horde_Core_Factory_TextFilter'); $filtered_subject = preg_replace("/\\b\\s+\\b/", ' ', IMP::filterText($subject)); $result['subject'] = $text_filter->filter($filtered_subject, 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::NOHTML)); $subjectlink = $text_filter->filter($filtered_subject, 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO)); if ($subjectlink != $result['subject']) { $result['subjectlink'] = $subjectlink; } if (!$preview) { $result['title'] = $subject; } } else { $result['subject'] = _("[No Subject]"); if (!$preview) { $result['title'] = _("[No Subject]"); } } // Create message text and attachment list. $result['msgtext'] = ''; $show_parts = $prefs->getValue('parts_display'); switch ($registry->getView()) { case $registry::VIEW_SMARTMOBILE: $contents_mask = 0; break; default: $contents_mask = IMP_Contents::SUMMARY_BYTES | IMP_Contents::SUMMARY_SIZE | IMP_Contents::SUMMARY_ICON | IMP_Contents::SUMMARY_DESCRIP_LINK | IMP_Contents::SUMMARY_DOWNLOAD | IMP_Contents::SUMMARY_DOWNLOAD_ZIP | IMP_Contents::SUMMARY_PRINT_STUB; break; } $part_info = $part_info_display = array('icon', 'description', 'size', 'download', 'download_zip'); $part_info_display[] = 'print'; list($mbox, $uid) = $this->_indices->getSingle(); /* Do MDN processing now. */ switch ($registry->getView()) { case $registry::VIEW_DYNAMIC: if ($imp_ui->MDNCheck(new IMP_Indices($mbox, $uid), $mime_headers)) { $status = new IMP_Mime_Status(array(_("The sender of this message is requesting notification from you when you have read this message."), sprintf(_("Click %s to send the notification message."), Horde::link('#', '', '', '', '', '', '', array('id' => 'send_mdn_link')) . _("HERE") . '</a>'))); $status->domid('sendMdnMessage'); $result['msgtext'] .= strval($status); } } /* Build body text. This needs to be done before we build the * attachment list. */ $session->close(); $inlineout = $this->_contents->getInlineOutput(array('mask' => $contents_mask, 'part_info_display' => $part_info_display, 'show_parts' => $show_parts)); $session->start(); $result['md'] = $inlineout['metadata']; $result['msgtext'] .= $inlineout['msgtext']; if ($inlineout['one_part']) { $result['onepart'] = true; } if (count($inlineout['atc_parts']) || $show_parts == 'all' && count($inlineout['display_ids']) > 2) { $result['atc_label'] = $show_parts == 'all' ? _("Parts") : sprintf(ngettext("%d Attachment", "%d Attachments", count($inlineout['atc_parts'])), count($inlineout['atc_parts'])); if (count($inlineout['atc_parts']) > 2) { $result['atc_download'] = Horde::link($this->_contents->urlView($this->_contents->getMIMEMessage(), 'download_all')) . '[' . _("Save All") . ']</a>'; } } /* Show attachment information in headers? */ if (!empty($inlineout['atc_parts'])) { $partlist = array(); if ($show_parts == 'all') { array_unshift($part_info, 'id'); } foreach ($inlineout['atc_parts'] as $id) { $contents_mask |= IMP_Contents::SUMMARY_DESCRIP | IMP_Contents::SUMMARY_DOWNLOAD | IMP_Contents::SUMMARY_ICON | IMP_Contents::SUMMARY_SIZE; $part_info[] = 'description_raw'; $part_info[] = 'download_url'; $summary = $this->_contents->getSummary($id, $contents_mask); $tmp = array(); foreach ($part_info as $val) { if (isset($summary[$val])) { $tmp[$val] = $summary[$val] instanceof Horde_Url ? strval($summary[$val]->setRaw(true)) : $summary[$val]; } } $partlist[] = array_filter($tmp); } $result['atc_list'] = $partlist; } $result['save_as'] = IMP_Contents_View::downloadUrl(htmlspecialchars_decode($result['subject']), array_merge(array('actionID' => 'save_message'), $mbox->urlParams($uid))); if ($preview) { /* Need to grab cached inline scripts. */ Horde::startBuffer(); $page_output->outputInlineScript(true); if ($js_inline = Horde::endBuffer()) { $result['js'] = array($js_inline); } $result['save_as'] = strval($result['save_as']->setRaw(true)); } else { $list_info = $imp_ui->getListInformation($mime_headers); if (!empty($list_info['exists'])) { $result['list_info'] = $list_info; } } /* Add changed flag information. */ if (!$this->_peek && $mbox->is_imap) { $status = $mbox->imp_imap->status($mbox, Horde_Imap_Client::STATUS_PERMFLAGS); if (in_array(Horde_Imap_Client::FLAG_SEEN, $status['permflags'])) { $ajax_queue->flag(array(Horde_Imap_Client::FLAG_SEEN), true, $this->_indices); } } return array_filter($result); }