<?php
/**
 * $Horde: imp/mailbox.php,v 2.296.2.62 2004/03/26 22:43:24 jan Exp $
 *
 * Copyright 1999-2004 Charles J. Hagenbuch <chuck@horde.org>
 * Copyright 1999-2004 Jon Parise <jon@horde.org>
 *
 * See the enclosed file COPYING for license information (GPL).  If you
 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
 */

function runSearch(&$sorted)
{
    global $imp, $folders, $prefs;

    $sorted = array();
    if (empty($imp['searchquery']) || empty($imp['searchfolders'])) {
        return array();
    }

    for ($i = 0; $i < count($imp['searchfolders']); $i++) {
        if (strstr($imp['protocol'], 'pop3')) {
            $stream = $imp['stream'];
        } else {
            $stream = @imap_open(IMP::serverString() . $imp['searchfolders'][$i],
                                 $imp['user'], Secret::read(Secret::getKey('imp'), $imp['pass']), OP_READONLY);
        }

        if ($stream) {
            if ($prefs->getValue('sortby') == SORTTHREAD) {
                $results = imap_sort($stream, SORTDATE,
                                     $prefs->getValue('sortdir'), SE_UID, $imp['searchquery']);
            } else {
                $results = imap_sort($stream, $prefs->getValue('sortby'),
                                     $prefs->getValue('sortdir'), SE_UID, $imp['searchquery']);
            }
            if (is_array($results)) {
                for ($j = 0; $j < count($results); $j++) {
                    $sorted[] = $results[$j];
                    $folders[] = $imp['searchfolders'][$i];
                }
            }
            if (!strstr($imp['protocol'], 'pop3')) {
                imap_close($stream);
            }
        }
    }

    if (isset($folders)) {
        $imp['messagefolders'] = implode(':', $folders);
        return implode(':', $sorted);
    } else {
        return false;
    }
}

function stylize($string, $styles)
{
    if (!is_array($styles)) return $string;

    foreach ($styles as $style) {
        if (!empty($style)) {
            $string = '<' . $style . '>' . $string . '</' . $style . '>';
        }
    }

    return $string;
}

$set = false;
if (isset($new_lang)) {
    $language = $new_lang;
    $set = true;
}

define('IMP_BASE', dirname(__FILE__));
require_once IMP_BASE . '/lib/base.php';
require_once IMP_BASE . '/lib/Message.php';
require_once HORDE_BASE . '/lib/MIME.php';
require_once HORDE_BASE . '/lib/MIME/Part.php';
require_once HORDE_BASE . '/lib/MIME/Viewer.php';
require_once HORDE_BASE . '/config/mime_drivers.php';
require_once HORDE_BASE . '/config/mime_mapping.php';
require_once HORDE_BASE . '/config/html.php';
require_once IMP_BASE . '/config/html.php';
require_once IMP_BASE . '/config/mime_drivers.php';
require_once IMP_BASE . '/lib/Identity/IMP.php';

/* Initialize $actionID to a resonable value if it hasn't already been set. */
$actionID = Horde::getFormData('actionID');

if (empty($notification)) {
    require_once HORDE_BASE . '/lib/Notification.php';
    $notification = &Notification::singleton();
    $notification->attach('status');
}
$show_whitelist = $registry->hasMethod('filter/whitelistFrom');

IMP::checkAuthentication();

$newmail_popup = ($prefs->getValue('nav_popup') &&
                  (Horde::getFormData('newmail_popup') != 'no'));

if (($actionID == IMP_LOGIN) || ($actionID == LOGIN_COMPOSE)) {
    if (isset($new_lang)) {
        $language = $new_lang;
    }

    if ($actionID == LOGIN_COMPOSE) {
        if ($prefs->getValue('compose_popup')) {
            $open_compose_window = true;
        } else {
            $url = Horde::applicationUrl('compose.php', true);
            $url = IMP::addParameter($url, IMP::getComposeArgs());
            header('Location: ' . $url);
            exit;
        }
    }

    $newmail_popup = false;
}

/* Get form data and make sure it's the type that we're expecting. */
$targetMbox = Horde::getFormData('targetMbox');
$newMbox = Horde::getFormData('newMbox');
if (!is_array(($indices = Horde::getFormData('indices')))) {
    $indices = array($indices);
}

/* Set the current time zone. */
if ($prefs->getValue('timezone') != '') {
    putenv('TZ=' . $prefs->getValue('timezone'));
}

/* Check for sent-message confirmation. */
if (Horde::getFormData('compose_confirm')) {
    Horde::raiseMessage(_("Message sent successfully"), HORDE_SUCCESS);
}

/* Initialize the user's identities */
$identity = new Identity_IMP();

/* Run through the action handlers */
switch ($actionID) {

 case IMP_BLACKLIST:
     if ($registry->hasMethod('filter/blacklistFrom')) {
         $addresses = array();
         foreach ($indices as $msgnum) {
             $h = @imap_header($imp['stream'], imap_msgno($imp['stream'], $msgnum));
             if (isset($h->from[0])) {
                 $ob = $h->from[0];
                 $addr = Mime::trimEmailAddress(IMP::rfc822WriteAddress($ob->mailbox, $ob->host, ''));
                 $addresses[] = chop(trim($addr));
             }
         }
         $registry->call('filter/blacklistFrom', array($addresses));
     } else {
         $filters = @unserialize($prefs->getValue('filters'));
         foreach ($indices as $msgnum) {
             $h = @imap_header($imp['stream'], imap_msgno($imp['stream'], $msgnum));
             if (isset($h->from[0])) {
                 $ob = $h->from[0];
                 $addr = Mime::trimEmailAddress(IMP::rfc822WriteAddress($ob->mailbox, $ob->host, ''));
                 $filters[] = array('fields' => array('from'), 'text' => chop(trim($addr)), 'action' => 'delete');
             }
         }
         $prefs->setValue('filters', serialize($filters));
         $prefs->store();
         header('Location: ' . Horde::applicationUrl('filters.php'));
         exit;
     }
     break;

 case IMP_WHITELIST:
     if ($show_whitelist) {
         $addresses = array();
         foreach ($indices as $msgnum) {
             $h = @imap_header($imp['stream'], imap_msgno($imp['stream'], $msgnum));
             if (isset($h->from[0])) {
                 $ob = $h->from[0];
                 $addr = Mime::trimEmailAddress(IMP::rfc822WriteAddress($ob->mailbox, $ob->host, ''));
                 $addresses[] = chop(trim($addr));
             }
         }
         $registry->call('filter/whitelistFrom', array($addresses));
     }
     break;

 case MESSAGE_MISSING:
     Horde::raiseMessage(_("There was an error viewing the requested message."), HORDE_ERROR);
     break;

 case DELETE_MESSAGES:
     if (!empty($indices)) {
         IMP_Message::delete($indices);
         // For POP3, redirect so that refreshing the page doesn't
         // delete more messages accidentally.
         if ($imp['base_protocol'] == 'pop3') {
             header('Location: ' . Horde::applicationUrl('mailbox.php'), true);
             exit;
         }
     }
     break;

 case UNDELETE_MESSAGES:
     if (!empty($indices)) {
         IMP_Message::undelete($indices);
     }
     break;

 case MOVE_MESSAGES:
 case COPY_MESSAGES:
     if (!empty($indices) && !empty($targetMbox)) {
         if (!empty($newMbox) && $newMbox == 1) {
             $new_mailbox = IMP::addPreambleString(IMP::utf7Encode($targetMbox));

             include_once IMP_BASE . '/lib/Folder.php';
             if (IMP_Folder::create($imp['stream'],
                                    $new_mailbox,
                                    $prefs->getValue('subscribe'))) {
                 unset($imp['imaptree']);
                 IMP_Message::copy($new_mailbox, $indices, $actionID);
             }
         } else {
             IMP_Message::copy($targetMbox, $indices, $actionID);
         }
     }
     break;

 case FLAG_MESSAGES:
     if (!empty($indices) && !empty($_POST['flag'])) {
         if ($_POST['flag'][0] == '0') {
             $_POST['flag'] = '\\' . substr($_POST['flag'], 1);
             $set = false;
         } else {
             $_POST['flag'] = '\\' . $_POST['flag'];
             $set = true;
         }
         IMP_Message::flag($_POST['flag'], $indices, $set);
     }
     break;

 case HIDE_DELETED:
     $prefs->setValue('delhide', !$prefs->getValue('delhide'));
     break;

 case EXPUNGE_MAILBOX:
     if ($imp['mailbox'] == '**search') {
         for ($i = 0; $i < count($imp['searchfolders']); $i++) {
             if (strstr($imp['protocol'], 'pop3')) {
                 $stream = $imp['stream'];
             } else {
                 $stream = @imap_open(IMP::serverString() . $imp['searchfolders'][$i],
                                      $imp['user'], Secret::read(Secret::getKey('imp'), $imp['pass']));
             }
             if (!(@imap_expunge($stream))) {
                 Horde::raiseMessage(sprintf(_("There was a problem expunging %s. This is what the server said"), IMP::displayFolder($imp['searchfolders'][$i])) .
                                     ': <i>' . imap_last_error() . '</i>', HORDE_ERROR);
             }
             if (!strstr($imp['protocol'], 'pop3')) {
                 imap_close($stream);
             }
         }
     } else {
         if (!(@imap_expunge($imp['stream']))) {
             Horde::raiseMessage(_("There was a problem expunging the mailbox. This is what the server said") .
                                 ': <i>' . imap_last_error() . '</i>', HORDE_ERROR);
         }
     }
     break;

 case SEARCH:
     /* Create the search query with the given data. */
     $query = '';
     switch ($_POST['search_seen']) {
     case 0:
         $query .= ' SEEN';
         break;
     case 1:
         $query .= ' UNSEEN';
         break;
     default:
         break;
     }

     switch ($_POST['search_answered']) {
     case 0:
         $query .= ' ANSWERED';
         break;
     case 1:
         $query .= ' UNANSWERED';
         break;
     default:
         break;
     }

     switch ($_POST['search_flagged']) {
     case 0:
         $query .= ' FLAGGED';
         break;
     case 1:
         $query .= ' UNFLAGGED';
         break;
     default:
         break;
     }

     switch ($_POST['search_deleted']) {
     case 0:
         $query .= ' DELETED';
         break;
     case 1:
         $query .= ' UNDELETED';
         break;
     default:
         break;
     }

     if (!empty($_POST['search_from'])) {
         $query .= ' FROM "' . Horde::getFormData('search_from') . '"';
     }

     if (!empty($_POST['search_to'])) {
         $query .= ' TO "' . Horde::getFormData('search_to') . '"';
     }

     if (!empty($_POST['search_cc'])) {
         $query .= ' CC "' . Horde::getFormData('search_cc') . '"';
     }

     if (!empty($_POST['search_subject'])) {
         $query .= ' SUBJECT "' . Horde::getFormData('search_subject') . '"';
     }

     if (!empty($_POST['search_body'])) {
         $query .= ' BODY "' . Horde::getFormData('search_body') . '"';
     }

     if (!empty($_POST['search_on_month']) &&
         !empty($_POST['search_on_day']) &&
         !empty($_POST['search_on_year']) &&
         preg_match('/^\d{4}$/', $_POST['search_on_year'])) {
         $query .= ' ON "' . date('r', mktime(0, 0, 0, $_POST['search_on_month'], $_POST['search_on_day'], $_POST['search_on_year'])) . '"';
     }

     if (!empty($_POST['search_before_month']) &&
         !empty($_POST['search_before_day']) &&
         !empty($_POST['search_before_year']) &&
         preg_match('/^\d{4}$/', $_POST['search_before_year'])) {
         $query .= ' BEFORE "' . date('r', mktime(0, 0, 0, $_POST['search_before_month'], $_POST['search_before_day'], $_POST['search_before_year'])) . '"';
     }

     if (!empty($_POST['search_since_month']) &&
         !empty($_POST['search_since_day']) &&
         !empty($_POST['search_since_year']) &&
         preg_match('/^\d{4}$/', $_POST['search_since_year'])) {
         $query .= ' SINCE "' . date('r', mktime(0, 0, 0, $_POST['search_since_month'], $_POST['search_since_day'], $_POST['search_since_year'])) . '"';
     }

     $imp['searchquery'] = trim($query);
     $imp['searchfolders'] = $_POST['search_folders'];
     break;

 case FILTER:
     IMP::filterMailbox();
     break;

 case EMPTY_MAILBOX:
     $check = @imap_check($imp['stream']);
     if (is_object($check) && !empty($check->Nmsgs)) {
         if (!IMP_Message::delete('1:*')) {
             Horde::raiseMessage(sprintf(_("There was a problem expunging the mailbox. This is what the server said: %s"), imap_last_error()), HORDE_ERROR);
         } else {
             Horde::raiseMessage(sprintf(_("Cleared all messages from %s."), IMP::displayFolder($imp['thismailbox'])), HORDE_SUCCESS);
         }
     }
     if ($url = Horde::getFormData('return_url')) {
         header('Location: ' . str_replace('&amp;', '&', $url));
         exit;
     }
     break;
}

if ($conf['user']['allow_folders']) {
    $options = IMP::flistSelect(_("Messages to"), true, array($imp['mailbox']), null, true);
}

$newmsgs = 0;
if ($imp['mailbox'] == '**search') {
    $imp['msgl'] = runSearch($sorted);
    $imp['msgcount'] = count($sorted);
} else {
    if ($prefs->getValue('delhide')) {
        $msgs = imap_search($imp['stream'], 'UNDELETED');
        $imp['msgcount'] = ($msgs !== false) ? count($msgs) : 0;
        if ($newmail_popup) {
            $new = imap_search($imp['stream'], 'RECENT UNDELETED');
            $newmsgs = $new ? count($new) : 0;
        }
    } else {
        $check = imap_check($imp['stream']);
        $imp['msgcount'] = (is_object($check) && isset($check->Nmsgs)) ? $check->Nmsgs : 0;
        if ($newmail_popup) {
            $new = imap_search($imp['stream'], 'RECENT');
            $newmsgs = $new ? count($new) : 0;
        }
    }

    if ($imp['msgcount'] != 0) {
        if ($prefs->getValue('sortby') != SORTTHREAD) {
            if ($prefs->getValue('delhide')) {
                $sorted = imap_sort($imp['stream'], $prefs->getValue('sortby'),
                                    $prefs->getValue('sortdir'), SE_UID, 'UNDELETED');
            } else {
                $sorted = imap_sort($imp['stream'], $prefs->getValue('sortby'),
                                    $prefs->getValue('sortdir'), SE_UID);
            }
        } else {
            IMP_Message::threadSort();
        }
        if (count($sorted) == 0) {
            $sorted = array();
            for ($i = 1; $i < $imp['msgcount'] + 1; $i++) {
                $sorted[] = imap_uid($imp['stream'], $i);
            }
        }
    } else {
        $sorted = array();
    }
}

/* Paging logic. This should be cleaned up if at all possible. */
if ($imp['msgcount'] > $prefs->getValue('max_msgs')) {

    $page_count = ceil($imp['msgcount'] / (($prefs->getValue('max_msgs') > 0) ? $prefs->getValue('max_msgs') : 20));

    /* Determine which page to display */
    $f_page = Horde::getFormData('page');
    $f_start = Horde::getFormData('start');

    if (!empty($f_page) && !strcspn($f_page, '0123456789')) {
        /* This will be sanity checked later. */
        $page = $f_page;

    } elseif (!empty($f_start)) {
        /* messages set this when returning to a mailbox */
        $page = ceil($f_start / $prefs->getValue('max_msgs'));

    } elseif ($imp['mailbox'] != '**search' && $prefs->getValue('sortby') != SORTTHREAD) {
        /* Use imap_sort to find the first unread message */
        if ($prefs->getValue('delhide')) {
            $search = 'UNSEEN UNDELETED';
        } else {
            $search = 'UNSEEN';
        }
        $new = imap_sort($imp['stream'], $prefs->getValue('sortby'),
                         $prefs->getValue('sortdir'), SE_UID, $search);
        if (!empty($new)) {
            $msg_keys = array_flip($sorted);
            $first_new = $msg_keys[$new[0]] + 1;
            $page = ceil($first_new / $prefs->getValue('max_msgs'));
        } else {
            $page = $prefs->getValue('sortdir') ? 1 : $page_count;
        }
    } else {
        $page = $prefs->getValue('sortdir') ? 1 : $page_count;
    }

    /* Make sure we're not past the end or before the beginning, and
     * that we have an integer value. */
    $page = intval($page);
    if ($page > $page_count) {
        $page = $page_count;
    } elseif ($page < 1) {
        $page = 1;
    }

    $begin = (($page - 1) * $prefs->getValue('max_msgs')) + 1;
    $end = $begin + $prefs->getValue('max_msgs') - 1;
    if ($end > $imp['msgcount']) {
        $end = $imp['msgcount'];
    }

    if ($page == 1) {
        if ($browser->hasFeature('images')) {
            $pages_first = Horde::img('first-grey.gif');
            $pages_prev = Horde::img('prev-grey.gif');
        } else {
            $pages_first = '';
            $pages_prev  = '';
        }
    } else {
        $prev = $page - 1;
        $first_url = Horde::applicationUrl('mailbox.php?page=1');
        $prev_url  = Horde::applicationUrl("mailbox.php?page=$prev");
        if ($browser->hasFeature('images')) {
            $pages_first = Horde::link($first_url, _("First Page"), 'widget');
            $pages_first .= Horde::img('first.gif', 'alt="' . _("First Page") . '"');
            $pages_first .= '</a>';
            $pages_prev = Horde::link($prev_url, _("Previous Page"), 'widget');
            $pages_prev .= Horde::img('prev.gif', 'alt="' . _("Previous Page") . '"');
            $pages_prev .= '</a>';
        } else {
            $pages_first = Horde::link($first_url, _("First Page"), 'widget');
            $pages_first .= '&lt;&lt; [ ' . _("First Page") . ' ]</a>';
            $pages_prev = Horde::link($prev_url, _("Previous Page"), 'widget');
            $pages_prev .= '&lt; [ ' . _("Previous Page") . ' ]</a>';
        }
    }

    if ($page == $page_count) {
        if ($browser->hasFeature('images')) {
            $pages_last = Horde::img('last-grey.gif');
            $pages_next = Horde::img('next-grey.gif');
        } else {
            $pages_last = '';
            $pages_next = '';
        }
    } else {
        $next = $page + 1;
        $next_url = Horde::applicationUrl("mailbox.php?page=$next");
        $last_url = Horde::applicationUrl("mailbox.php?page=$page_count");

        if ($browser->hasFeature('images')) {
            $pages_next = Horde::link($next_url, _("Next Page"), 'widget');
            $pages_next .= Horde::img('next.gif', 'alt="' . _("Next Page") . '"');
            $pages_next .= '</a>';
            $pages_last = Horde::link($last_url, _("Last Page"), 'widget');
            $pages_last .= Horde::img('last.gif', 'alt="' . _("Last Page") . '"');
            $pages_last .= '</a>';
        } else {
            $pages_next = Horde::link($next_url, _("Next Page"), 'widget');
            $pages_next .= '[ ' . _("Next Page") . ' ] &gt;</a>';
            $pages_last = Horde::link($last_url, _("Last Page"), 'widget');
            $pages_last .= '[ ' . _("Last Page") . ' ] &gt;&gt;</a>';
        }
    }
} else {
    $begin = 1;
    $end = $imp['msgcount'];
    $page = 1;
}

if ($imp['mailbox'] == '**search') {
    $imp['offset'] = 0;
    $beginIndex = $begin - 1;
} else {
    $imp['msgl'] = implode(':', IMP_Message::range($sorted, $begin, $offset, $beginIndex, $num));
    $imp['offset'] = $offset;
}

if ($prefs->getValue('delhide')) {
    $deleted_prompt = _("Show Deleted");
} else {
    $deleted_prompt = _("Hide Deleted");
}

if ($end != 0) {
    $msg_count = sprintf(_("%d to %d of %d Messages"), $begin, $end, $imp['msgcount']);
} else {
    $msg_count = sprintf(_("%d of %d Messages"), $end, $imp['msgcount']);
}

/* If user wants the mailbox to be refreshed, set time here */
$refresh_time = $prefs->getValue('refresh_time');
$refresh_url = Horde::applicationUrl("mailbox.php?page=$page&uniq=" . uniqid(rand()));
if ($prefs->getValue('filter_on_refresh') && $imp['mailbox'] != IMP::preambleString() . $prefs->getValue('trash_folder')) {
    $refresh_url = IMP::addParameter($refresh_url, 'actionID=' . FILTER);
}

$title = $imp['label'];
$js_onLoad = null;
if ($conf['compress_pages']) {
    ob_start('ob_gzhandler');
}

require IMP_TEMPLATES . '/common-header.inc';
if ($browser->hasFeature('javascript')) {
    include IMP_TEMPLATES . '/mailbox/javascript.inc';
}
require IMP_BASE . '/menu.php';
require IMP_BASE . '/status.php';
$notification->notify();

if (!empty($conf['hooks']['quota']) && function_exists($conf['hooks']['quota'])) {
    echo call_user_func($conf['hooks']['quota'], $imp);
}

require IMP_TEMPLATES . '/mailbox/header.inc';
$navform = 1;
require IMP_TEMPLATES . '/mailbox/navbar.inc';
require IMP_TEMPLATES . '/mailbox/actions.inc';
if ($imp['mailbox'] != '**search') {
    include IMP_TEMPLATES . '/mailbox/message_headers.inc';
}

// Build the array of message information,
$sortedIds = array_flip($sorted);
$mailboxOverview = array();
for ($i = ($begin - 1), $j = $beginIndex, $msgs = array(), $extra = array(); $i < $end; $i++, $j++) {
    /* Make sure that the index is actually in the slice of messages
       we're looking at. If we're hiding deleted messages, for
       example, there may be gaps here. */
    if (isset($sorted[$i])) {
        if ($imp['mailbox'] === '**search') {
            if (($j === $beginIndex) || ($folders[$j - 1] !== $folders[$j])) {
                if (count($msgs) > 0) {
                    $overview = imap_fetch_overview($imp['stream'], implode(',', $msgs), FT_UID);
                    $msgs = array();
                    foreach ($overview as $header) {
                        $mailboxOverview[$sortedIds[$header->uid]]['header'] = $header;
                        $mailboxOverview[$sortedIds[$header->uid]]['folder'] = $folders[$j - 1];
                        $mailboxOverview[$sortedIds[$header->uid]]['structure'] = $extra[$header->uid]['structure'];
                    }
                }

                if (!strstr($imp['protocol'], 'pop3')) {
                    imap_reopen($imp['stream'], IMP::serverString() . $folders[$j],
                                OP_READONLY);
                }
            }
        }

        $msgs[] = $sorted[$i];
        if ($conf['mailbox']['show_attachments']) {
            $extra[$sorted[$i]]['structure'] = @imap_fetchstructure($imp['stream'], $sorted[$i], FT_UID);
        } else {
            $extra[$sorted[$i]]['structure'] = null;
        }
    }
}
if (count($msgs) > 0) {
    $overview = imap_fetch_overview($imp['stream'], implode(',', $msgs), FT_UID);
    foreach ($overview as $header) {
        $mailboxOverview[$sortedIds[$header->uid]]['header'] = $header;
        $mailboxOverview[$sortedIds[$header->uid]]['structure'] = $extra[$header->uid]['structure'];
        if ($imp['mailbox'] === '**search') {
            $mailboxOverview[$sortedIds[$header->uid]]['folder'] = $folders[$j - 1];
        }
    }
}

// Get everything in the right sort order
ksort($mailboxOverview);

// Display message information.
$curr_time = time();
$curr_time -= ($curr_time % 60);
foreach ($mailboxOverview as $key => $message) {
    if ($imp['mailbox'] == '**search') {
        if (!isset($lastFolder) || ($message['folder'] != $lastFolder)) {
            include IMP_TEMPLATES . '/mailbox/searchfolder.inc';
            include IMP_TEMPLATES . '/mailbox/message_headers.inc';
        }
        $lastFolder = $message['folder'];
    }

    /* initialize the header fields */
    $dat = '';
    $frm = '';
    $fullfrom = '';
    $to = '';
    $sub = '';
    $msg_size = '?';

    /* Now pull the IMAP header values into them, decoding them at
       the same time. */
    $h = $message['header'];

    /* formats the header date string nicely */
    if (!empty($h->date) && ($udate = strtotime($h->date, $curr_time)) != -1) {
        if ((date('Y') != @date('Y', $udate)) ||
            (date('M') != @date('M', $udate)) ||
            (date('d') != @date('d', $udate))) {
            // not today, use the date
            $dat = @strftime($conf['mailbox']['date_format'], $udate);
        } else {
            // else it's today, use the time
            $dat = @strftime($conf['mailbox']['time_format'], $udate);
        }
    } else {
        $dat = '';
    }

    if (isset($h->from)) {
        $tmp = imap_rfc822_parse_adrlist($h->from, '');
        $tmp = $tmp[0];
        $fullfrom = '';

        if (isset($tmp->personal)) {
            $fullfrom = $frm = MIME::decode($tmp->personal);
        }

        if (isset($tmp->mailbox) && isset($tmp->host)) {
            if (empty($frm)) $frm = $tmp->mailbox . '@' . $tmp->host;
            $fullfrom .= $tmp->mailbox . '@' . $tmp->host;
        }
    }

    if ($identity->hasAddress($fullfrom)) {
        if (isset($h->to)) {
            $tmp = imap_rfc822_parse_adrlist($h->to, '');
            $tmp = $tmp[0];
            if (isset($tmp->personal)) {
                $to = MIME::decode($tmp->personal);
            }
            if (empty($to) && isset($tmp->mailbox) && isset($tmp->host)) {
                $to = $tmp->mailbox . '@' . $tmp->host;
            }
        } else {
            $to = _("Undisclosed Recipients");
        }
        $frm = _("To") . ': ' . $to;
    }

    if (isset($h->subject)) {
        $sub = MIME::decode($h->subject);
    }
    if (isset($h->size)) {
        $msg_size = ($h->size > 1024)
            ? sprintf('%.0fkb', $h->size / 1024)
            : $h->size;
    }
    if (strlen($frm) > $conf['mailbox']['max_from_chars']) {
        $frm = substr($frm, 0, $conf['mailbox']['max_from_chars']) . '...';
    }

    if ($prefs->getValue('sortby') != SORTTHREAD || $imp['mailbox'] == '**search') {
        if (strlen($sub) > $conf['mailbox']['max_subj_chars']) {
            $sub = substr($sub, 0, $conf['mailbox']['max_subj_chars']) . '...';
        }
    } else {
        $maxlen = $conf['mailbox']['max_subj_chars'] - 3 * $indentLevel[$h->uid];
        if ($maxlen < 5) {
            $maxlen = 5;
        }
        if (strlen($sub) > $maxlen) {
            $sub = substr($sub, 0, $maxlen) . '...';
        }
    }

    /* set them to useful things for IMP if they ended up being empty */
    if ($dat == '') { $dat = '&nbsp;'; }
    if ($frm == '') { $frm = '&nbsp;'; }
    if ($sub == '') { $sub = '[' . _("No Subject") . ']'; }

    /* filter the subject text, if requested */
    if ($prefs->getValue('filtering')) {
        include_once HORDE_BASE . '/lib/Text.php';
        $sub = Text::filter($sub, $conf['msg']['filtering']['words'],
                            $conf['msg']['filtering']['replacement']);
    }

    $attachment = false;
    if (isset($message['structure'])) {
        if (!empty($message['structure']->subtype)) {
            if (strtolower($message['structure']->subtype) == 'signed' ||
                strtolower($message['structure']->subtype) == 'encrypted') {
                $attachment = 'signed';
            } elseif (strtolower($message['structure']->subtype) == 'alternative') {
                $attachment = 'alternative';
            } elseif (isset($message['structure']->parts) &&
                      is_array($message['structure']->parts) &&
                      count($message['structure']->parts) > 0) {
                $attachment = 'attachment';
            } elseif ((!empty($message['structure']->type) &&
                       $message['structure']->type != TYPETEXT) ||
                      !empty($message['structure']->subtype) &&
                      strtolower($message['structure']->subtype) != 'plain') {
                $attachment = 'attachment';
            }
        }
    }

    if ($imp['mailbox'] == '**search') {
        $target = Horde::applicationUrl('message.php?mailbox=**search&thismailbox=' .
                                        urlencode($message['folder']) .
                                        '&index=' . $h->uid);
    } else {
        $target = Horde::applicationUrl('message.php?index=' . $h->uid);
    }

    /* get all the flag information */
    $flagbits = 0;
    $style = array();
    $status = '';
    $bg = 'text';
    if (!strstr($imp['protocol'], 'pop3')) {
        if (!empty($h->to) && $identity->hasAddress($h->to)) {
            $status .= $conf['mailbox']['personal_flag'];
            $flagbits |= IMP_PERSONAL;
        }
        if (!$h->seen) {
            $flagbits |= IMP_UNSEEN;
            $status .= $conf['mailbox']['unseen_flag'];
            $style[] = $conf['mailbox']['unseen_style'];
            $bg = 'unseen';
        }
        if ($h->answered) {
            $flagbits |= IMP_ANSWERED;
            $status .= $conf['mailbox']['answered_flag'];
            $style[] = $conf['mailbox']['answered_style'];
            $bg = 'answered';
        }
        if ($h->draft) {
            $flagbits |= IMP_DRAFT;
            $status .= $conf['mailbox']['draft_flag'];
            $style[] = $conf['mailbox']['draft_style'];
            $target = IMP::composeLink(array(), array('actionID' => DRAFT, 'mailbox' => $imp['mailbox'], 'index' => $h->uid, 'bodypart' => 1));
        }
        if ($h->flagged) {
            $flagbits |= IMP_FLAGGED;
            $status .= $conf['mailbox']['important_flag'];
            $style[] = $conf['mailbox']['important_style'];
            $bg = 'important';
        }
        if ($h->deleted) {
            $flagbits |= IMP_DELETED;
            $status .= $conf['mailbox']['deleted_flag'];
            $style[] = $conf['mailbox']['deleted_style'];
            $bg = 'deleted';
        }
        $flags[] = $flagbits;
    } else {
        $flags[] = 0;
    }

    // apply styles
    $styledat = stylize($dat, $style);
    $stylefrm = stylize(htmlspecialchars($frm), $style);
    $stylesub = stylize(htmlspecialchars($sub), $style);
    if ($prefs->getValue('sortby') == SORTTHREAD && $imp['mailbox'] != '**search') {
        $stylesub = ($indentLevel[$h->uid] > 2 ? Horde::img('folders/spacer.gif', 'height="1" width="' . ($indentLevel[$h->uid] - 2) * 20 . '"') : '') . ($indentLevel[$h->uid] > 1 ? Horde::img('thread.gif', 'alt="-" width="14" height="14" border="0" align="absmiddle"') . '&nbsp;&nbsp;' : '') . $stylesub;
    }

    // set the message number
    $msg_number = $h->msgno;

    // decide what to do in the from column (after we've possibly
    // applied styles to $from)
    if ($conf['mailbox']['from_link'] == 'message') {
        if ($imp['mailbox'] == '**search') {
            $from_uri = Horde::applicationUrl('message.php?mailbox=**search&thismailbox=' .
                                              urlencode($message['folder']) .
                                              '&index=' . $h->uid);
        } else {
            $from_uri = Horde::applicationUrl('message.php?index=' . $h->uid);
        }
        $from_link = Horde::link($from_uri, $frm) . $stylefrm . '</a>';
    } elseif ($conf['mailbox']['from_link'] == 'compose') {
        if ($imp['mailbox'] == '**search') {
            $array_index = $key;
        }
        $compose_url = IMP::composeLink(array(), array('actionID' => MAILTO, 'mailbox' => $imp['mailbox'], 'index' => $h->uid));
        $from_link = Horde::link($compose_url, sprintf(_("Compose Message (%s)"), $frm)) . $stylefrm . '</a>';
    } else {
        $from_link = $stylefrm;
    }

    include IMP_TEMPLATES . '/mailbox/message_summaries.inc';
}

if ($end == 0) {
    if ($imp['mailbox'] == '**search') {
        include IMP_TEMPLATES . '/mailbox/message_headers.inc';
    }
    include IMP_TEMPLATES . '/mailbox/empty_mailbox.inc';
}

require IMP_TEMPLATES . '/mailbox/message_footers.inc';
if ($prefs->getValue('show_legend') && ($imp['base_protocol'] != 'pop3')) {
    include IMP_TEMPLATES . '/mailbox/legend.inc';
}
require IMP_TEMPLATES . '/mailbox/actions.inc';
$navform = 2;
require IMP_TEMPLATES . '/mailbox/navbar.inc';
require IMP_TEMPLATES . '/mailbox/footer.inc';

if ($newmail_popup && ($newmsgs > 0)) {
    include IMP_TEMPLATES . '/mailbox/alert.inc';
}

$registry->shutdown();
if (!empty($open_compose_window)) {
    $registry->pcall('mail/composePopup', array('options' => IMP::getComposeArgs('array')));
}

require IMP_TEMPLATES . '/common-footer.inc';

$prefs->store();

// catch error messages from c-client
imap_errors();
