<?php

require_once 'Horde/MIME/Headers.php';
require_once IMP_BASE . '/lib/version.php';

/** @constant IMP_AGENT_HEADER The description of the IMP program to use in the 'User-Agent:' header. */
define('IMP_AGENT_HEADER', 'Internet Messaging Program (IMP) ' . IMP_VERSION);

/**
 * The IMP_Headers:: class contains all functions related to handling
 * the headers of mail messages in IMP.
 *
 * $Horde: imp/lib/MIME/Headers.php,v 1.92.2.3 2005/01/20 15:26:04 chuck Exp $
 *
 * Copyright 2002-2005 Michael Slusarz <slusarz@bigworm.colorado.edu>
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
 *
 * @author  Michael Slusarz <slusarz@bigworm.colorado.edu>
 * @since   IMP 4.0
 * @package IMP
 */
class IMP_Headers extends MIME_Headers {

    /**
     * The User-Agent string to use.
     *
     * @var string $_agent
     */
    var $_agent = IMP_AGENT_HEADER;

    /**
     * Returns a reference to a currently open IMAP stream.
     *
     * @see MIME_Headers::_getStream()
     */
    function &_getStream()
    {
        return $GLOBALS['imp']['stream'];
    }

    /**
     * Parse all of the available mailing list headers.
     *
     * @access public
     */
    function parseAllListHeaders()
    {
        foreach ($this->listHeaders() as $val => $str) {
            $this->parseListHeaders($val);
        }
    }

    /**
     * Parse the information in the mailing list headers.
     *
     * @param string $header         The header to process.
     * @param optional boolean $raw  Should the raw URL be returned instead
     *                               of setting the header value?
     *
     * @return string  The header value (if $raw == true).
     */
    function parseListHeaders($header, $raw = false)
    {
        if (!($data = $this->getValue($header))) {
            return;
        }

        $output = '';

        require_once 'Horde/Text.php';

        /* Split the incoming data by the ',' character. */
        foreach (preg_split("/,/", $data) as $entry) {
            /* Get the data inside of the brackets. If there is no brackets,
               then return the raw text. */
            if (!preg_match("/\<([^\>]+)\>/", $entry, $matches)) {
                return trim($entry);
            }

            /* Remove all whitespace from between brackets (RFC 2369 [2]). */
            $match = preg_replace("/\s+/", '', $matches[1]);

            /* Determine if there is any comments. */
            preg_match("/(\(.+\))/", $entry, $comments);

            /* RFC 2369 [2] states that we should only show the *FIRST* URL
               that appears in a header that we can adequately handle. */
            if (stristr($match, 'mailto:') !== false) {
                $match = substr($match, strpos($match, ':') + 1);
                if ($raw) {
                    return $match;
                }
                $output = Horde::link(IMP::composeLink($match)) . $match . '</a>';
                if (!empty($comments[1])) {
                    $output .= '&nbsp;' . $comments[1];
                }
                break;
            } else {
                require_once 'Horde/Text/Filter.php';
                if ($url = Text_Filter::filter($match, 'linkurls', array('callback' => 'Horde::externalUrl'))) {
                    if ($raw) {
                        return $match;
                    }
                    $output = $url;
                    if (!empty($comments[1])) {
                        $output .= '&nbsp;' . $comments[1];
                    }
                    break;
                } else {
                    /* Use this entry unless we can find a better one. */
                    $output = $match;
                }
            }
        }

        $this->setValue($header, $output);
    }

    /**
     * Add any site-specific headers defined in config/header.txt to
     * the internal header array.
     *
     * @access public
     */
    function addSiteHeaders()
    {
        global $conf;

        /* Add the 'User-Agent' header. */
        $this->addAgentHeader();

        /* Tack on any site-specific headers. */
        if ($conf['msg']['prepend_header'] &&
            @is_readable(IMP_BASE . '/config/header.txt')) {
            include_once 'Horde/Text/Filter.php';

            $lines = @file(IMP_BASE . '/config/header.txt');
            foreach ($lines as $line) {
                $line = Text_Filter::filter($line, 'environment');
                if (!empty($line)) {
                    list($key, $val) = explode(':', $line, 2);
                    $this->addHeader(trim($key), trim($val));
                }
            }
        }
    }

    /**
     * Builds a string containing a list of addresses.
     *
     * @access public
     *
     * @param string $field           The address field to parse.
     * @param integer $addURL         The self URL.
     * @param optional boolean $set   Set the associated header with the
     *                                return string?
     * @param optional boolean $link  Link each address to the compose screen?
     *
     * @return string  String containing the formatted address list.
     */
    function buildAddressLinks($field, $addURL, $set = false, $link = true)
    {
        global $prefs, $registry;

        $add_link = null;

        /* Make sure this is a valid object address field. */
        $array = $this->getOb($field);
        if (empty($array) || !is_array($array)) {
            return null;
        }

        /* Set up the add address icon link if contact manager is
           available. */
        if ($link &&
            $registry->hasMethod('contacts/import') &&
            $prefs->getValue('add_source')) {
            $add_link = Util::addParameter($addURL, 'actionID', 'add_address');
        }

        $addr_array = array();

        foreach ($this->getAddressesFromObject($array) as $ob) {
            if (!empty($ob->address) && !empty($ob->inner)) {
                $ret = '';

                /* If this is an incomplete e-mail address, don't link
                   to anything. */
                if (stristr($ob->host, 'UNKNOWN') !== false) {
                    $ret = $ob->address;
                } else {
                    if ($link) {
                        $ret = Horde::link(IMP::composeLink(array('to' => $ob->address)), sprintf(_("Compose Message (%s)"), $ob->inner));
                        $ret .= htmlspecialchars($ob->address) . '</a>';
                    } else {
                        $ret = htmlspecialchars($ob->address);
                    }

                    /* Append the add address icon to every address if
                       contact manager is available. */
                    if ($add_link) {
                        $curr_link = Util::addParameter($add_link, array('name' => $ob->personal,
                                                                         'address' => $ob->inner));
                        $ret .= Horde::link($curr_link, sprintf(_("Add to Address book (%s)"), $ob->inner)) .
                            Horde::img('addressbook-blue.png', sprintf(_("Add to Address book (%s)"), $ob->inner), 'style="vertical-align:middle;padding:1px"') . '</a>';
                    }
                }

                $addr_array[] = $ret;
            }
        }

        /* If left with an empty address list ($ret), inform the user that
           the recipient list is purposely "undisclosed". */
        if (empty($addr_array)) {
            $ret = _("Undisclosed Recipients");
        } else {
            /* Build the address line. */
            $ret = '<span style="white-space:nowrap">' . implode(',</span> <span style="white-space:nowrap">', $addr_array) . '</span>';
        }

        /* Set the header value, if requested. */
        if (!empty($set)) {
            $this->setValue($field, $ret);
        }

        return $ret;
    }

    /**
     * Add the local time string to the date header.
     *
     * @access public
     *
     * @param string $date  The date string.
     *
     * @return string  The date string with the local time added on.
     */
    function addLocalTime($date)
    {
        if ($date && ($ltime = strtotime($date)) != -1) {
            $date_str = strftime($GLOBALS['prefs']->getValue('date_format'), $ltime);
            $time_str = strftime($GLOBALS['prefs']->getValue('time_format'), $ltime);
            $tz = strftime('%Z');
            if ((date('Y') != @date('Y', $ltime)) ||
                (date('M') != @date('M', $ltime)) ||
                (date('d') != @date('d', $ltime))) {
                /* Not today, use the date. */
                $date .= sprintf(' <small>[%s %s %s]</small>', $date_str, $time_str, $tz);
            } else {
                /* Else, it's today, use the time only. */
                $date .= sprintf(' <small>[%s %s]</small>', $time_str, $tz);
            }
        }

        return $date;
    }

}
