Location: PHPKode > projects > Zort > zort-1.1.0/index.php
<?
/**
 * Zort
 *
 * See docs/AUTHORS and docs/COPYING for relevant info.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * @version  $Id: index.php,v 1.56 2007/07/29 21:56:10 cyb0rg Exp $
 * @package  zort
 */

/**
 * Feed class
 *
 * This class keeps track of individual feeds which Zort will be loading.
 * Parameters like the number of items to show and the title to be displayed
 * are stored in here.
 */
class Feed
{
    var $_url;
    var $_numitems;
    var $_title;

    var $_magpie_fetched;
    var $_magpie_error;

    /**
     * Feed constructor
     *
     * @param string $url The URL of the feed
     * @param int $numitems The number of items to show from the feed (-1 == all items)
     * @param string $title The title to display when rendering the feed
     */
    function Feed($url, $numitems=-1, $title='')
    {
        $this->_url = $url;
        $this->_numitems = $numitems;
        $this->_title = $title;
        $this->_magpie_fetched = null;
        $this->_magpie_error = null;
    }

    /**
     * Return the number of items which will be shown
     * @return int The number of items
     */
    function maxitems()
    {
        return $this->_numitems;
    }

    /**
     * Return the title that we'll be using to display the feed
     * @return string The title we're using
     */
    function overridetitle()
    {
        return $this->_title;
    }

    /**
     * Fetches the feed from the internet
     * @return bool
     */
    function fetch()
    {
        $this->_magpie_fetched = fetch_rss($this->_url);
        if (!$this->_magpie_fetched)
        {
            $this->_magpie_error = magpie_error();
        }
        return (is_null($this->_magpie_error));
    }

    /**
     * Returns the data fetched from the internet
     * @return mixed The MagpieRSS object
     */
    function data()
    {
        return $this->_magpie_fetched;
    }

    /**
     * Explicitly set the data, as if we've fetched from the internet
     * @param mixed $newdata A MagpieRSS object
     */
    function set_data($newdata)
    {
        $this->_magpie_fetched = $newdata;
    }

    /**
     * Returns the magpie error, if there was one
     * @return string The error
     */
    function error()
    {
        return $this->_magpie_error;
    }

    /**
     * Returns true if we successfully fetched the feed
     * @return bool
     */
    function is_valid()
    {
        return (is_null($this->_magpie_error));
    }

    /**
     * Returns true if there was an error fetching the feed
     * @return bool
     */
    function is_error()
    {
        return (!$this->is_valid());
    }

    /**
     * Return the URL for the feed
     * @return string The URL
     */
    function get_url()
    {
        return $this->_url;
    }

    /**
     * Return how many items were actually fetched from the internet
     * @return int The count of items
     */
    function item_count()
    {
        return count($this->_magpie_fetched->items);
    }
}

/**
 * The main Zort class, which keeps track of all the feeds that we'll
 * be loading.
 */
class Zort
{
    var $pages = array();
    var $curpageidx = -1;
    var $curcatidx = -1;
    var $max_items = -1;
    var $showloadingpage = true;
    var $fixhtml = true;
    var $globaltitle = 'Zort';
    var $version = '1.1.0';

    /**
     * Returns the list of pages that we can draw
     * @return array An array of strings
     */
    function getpages()
    {
        return $this->pages;
    }

    /**
     * Add a new page to our list of pages
     * @param string $pagename The name of the page
     */
    function page($pagename)
    {
        $this->curpageidx++;
        $tempcats = array();
        $tempfeeds = array();
        $this->pages[] = array($tempcats, $tempfeeds, $pagename);
        $this->curcatidx = -1;
    }

    /**
     * Add a new category to the current page
     * @param string $catname The name of the category
     */
    function cat($catname)
    {
        if ($this->curpageidx == -1)
        {
            $this->page('default');
        }
        $this->curcatidx++;
        $this->pages[$this->curpageidx][0][] = $catname;
        $this->pages[$this->curpageidx][1][$catname] = array();
    }

    /**
     * Creates a new feed in the current category, allowing the user to
     * specify how many items to show in the feed, and the displayed title
     * of the feed.
     * @param string $feedname The URL of the feed
     * @param int $max The number of items to show in the feed
     * @param int $title The title to show while rendering
     */
    function feed_full($feedname, $max=-1, $title='')
    {
        if ($max == -1 and $this->max_items != -1)
        {
            $max = $this->max_items;
        }
        if ($this->curcatidx == -1)
        {
            $this->cat('default');
        }
        $catname = $this->pages[$this->curpageidx][0][$this->curcatidx];
        $this->pages[$this->curpageidx][1][$catname][] = new Feed($feedname, $max, $title);
    }

    /**
     * Adds one or more feeds to the current category.  The number of items
     * to display or feed title cannot be overridden using this method
     * @param string|array $newfeed A URL of of the feed, or an array of URLs, or any combination of the two
     */
    function feed()
    {
        foreach(func_get_args() as $newfeed)
        {
            if (is_array($newfeed))
            {
                $this->feed($newfeed);
            }
            else
            {
                $this->feed_full($newfeed);
            }
        }
    }

    /**
     * Sets the global limit on maximum items to be displayed (can be overridden with feed_full)
     * @param int $numitems The number of items to limit
     */
    function max_items($numitems)
    {
        $this->max_items = $numitems;
    }

    /**
     * Sets the title of the whole Zort page (default is "Zort")
     * @param string $title The new title
     */
    function title($title)
    {
        $this->globaltitle = $title;
    }

    /**
     * Gets the current title of the whole Zort page
     * @return string The title
     */
    function get_title()
    {
        return $this->globaltitle;
    }

    /**
     * Don't show the initial "loading" screen while loading feeds
     */
    function no_loading_screen()
    {
        $this->showloadingpage = false;
    }

    /**
     * Don't attempt to fix improper HTML in feeds
     */
    function no_fix_html()
    {
        $this->fixhtml = false;
    }

    // Here's some functions to deal with coloration.
    // We're keeping $colors as a global variable, btw, for backwards
    // compatibility.  *really* it should live inside the $zort object.
    // Ah, well.

    /**
     * Clear the default color array
     * @global array $colors
     */
    function color_reset()
    {
        global $colors;
        $colors = array();
    }

    /**
     * Add a new color to use, to the end of the color cycle
     * @param string $header Color to use as the feed header background (should be dark)
     * @param string $body Color to use as the feed body background (should be light)
     * @global array $colors
     */
    function color_add($header, $body)
    {
        global $colors;
        $colors[] = array($header, $body);
    }

    /**
     * Insert a new color to use, to the beginning of the color cycle
     * @param string $header Color to use as the feed header background (should be dark)
     * @param string $body Color to use as the feed body background (should be light)
     * @global array $colors
     */
    function color_insert($header, $body)
    {
        global $colors;
        array_unshift($colors, array($header, $body));
    }
}

/**
 * Draw the Zort HTML header.  Includes the stylesheet and related Javascript
 * functions, if necessary.
 *
 * @param string $title Addition to the default HTML title
 * @param bool $dojavascript Do we need to display Javascript functions?
 * @global array $colors
 * @global array $rsses
 * @global array $catstouse
 * @global bool $usingopera
 */
function drawHeader($title, $dojavascript=true)
{
    // Meh, don't really like using globals like this
    global $colors;
    global $rsses;
    global $catstouse;
    global $usingopera;
    ?>
<html>
<head>
<title><?=$title?></title>
<style type="text/css">
<!--
body {
    font-family: sans-serif;
    font-size: 0.75em;
    margin: 10;
    padding: 10;
}

a {
    color: #333;
    font-size: 1.20em;
}

strong {
    font-size: 0.85em;
}

.articletext {
    background-color: white;
    border: 1px solid silver;
    padding: 5px;
    margin: 20;
}

.smalltext {
    font-size: 0.70em;
}

.smalltext a {
    font-size: 0.70em;
}

.link {
    text-decoration: underline;
    cursor: pointer;
}

.title {
    color: #fff;
    text-decoration: none;
}

.titleerror {
    color: #000;
    text-decoration: none;
}

.cattitle {
    color: #000;
    background-color: #ddd;
    font-size: 1.6em;
    padding-top: 7px;
    padding-left: 7px;
    padding-bottom: 5px;
}

.pagetitle {
    font-size: 2.5em;
}

.lastmodified {
    color: #fff;
    font-size: 0.7em;
    float: right;
    padding-right: 7px;
}

.version {
    color: #ddd;
}

    <?
    for ($i=0; $i<count($colors); $i++)
    {
        echo "#hcolor$i\t{ background-color: " . $colors[$i][0] . "; margin: 0 0 1px 0; padding-top: 5px; padding-left: 5px; padding-bottom: 3px; }\n";
        echo "#bcolor$i\t{ background-color: " . $colors[$i][1] . "; }\n";
    }
    ?>
//-->
</style>
    <?
    if ($dojavascript)
    {
        ?>
<script type="text/javascript">
<!--
var graphicre = /^(.*\/)?w[a-z]+\.png$/;
var numcats = <?=count($rsses)?>;
var numfeeds = new Array;
var numitems = new Array;
        <?
        for ($i=0; $i<count($rsses); $i++)
        {
            echo "numfeeds[$i] = " . count($rsses[$catstouse[$i]]) . ";\n";
            echo "numitems[$i] = new Array;\n";
            for ($j=0; $j<count($rsses[$catstouse[$i]]); $j++)
            {
                echo "numitems[$i][$j] = " . $rsses[$catstouse[$i]][$j]->item_count() . ";\n";
            }
        }
        ?>

function getElementObj(elementname)
{
    return document.getElementById(elementname);
}
function getElementGfx(elementname)
{
    return document.getElementById(elementname + 'img');
}
function switchTo(elementname, state)
{
    element = getElementObj(elementname);
    if (element)
    {
        gfx = getElementObj(elementname + 'img');
        if (state == 'on')
        {
            element.style.display = '<?= ($usingopera ? '' : 'inline') ?>';
            if (gfx)
            {
                if (graphicre.test(gfx.src))
                {
                    gfx.src = 'wminus.png';
                }
                else
                {
                    gfx.src = 'minus.png';
                }
            }
        }
        else
        {
            element.style.display = 'none';
            if (gfx)
            {
                if (graphicre.test(gfx.src))
                {
                    gfx.src = 'wplus.png';
                }
                else
                {
                    gfx.src = 'plus.png';
                }
            }
        }
    }
}
function flipDisplay(elementname)
{
    element = getElementObj(elementname);
    if (element)
    {
        if (element.style.display == '<?= ($usingopera ? '' : 'inline') ?>')
        {
            switchTo(elementname, 'off');
        }
        else
        {
            switchTo(elementname, 'on');
        }
    }
}

// Changes the visibility of all categories on the page
function flipAllCats(state)
{
    var i;
    for (i=0; i<numcats; i++)
    {
        if (state)
        {
            switchTo('cat' + i, state);
        }
        else
        {
            flipDisplay('cat' + i);
        }
    }
}

// Changes the visibility of all feeds in a Category
function flipFeed(state, whichcat)
{
    var i;
    for (i=0; i<numfeeds[whichcat]; i++)
    {
        if (state)
        {
            switchTo('cat' + whichcat + 'feed' + i, state);
        }
        else
        {
            flipDisplay('cat' + whichcat + 'feed' + i);
        }
    }
}

// Changes the visibility of all feeds on the page
function flipAllFeeds(state)
{
    var i;
    for (i=0; i<numcats; i++)
    {
        flipFeed(state, i);
    }
}

// Changes the visibility of all items in a category and feed
function flipArticle(state, whichcat, whichfeed)
{
    var i;
    for (i=0; i<numitems[whichcat][whichfeed]; i++)
    {
        if (state)
        {
            switchTo('cat' + whichcat + 'feed' + whichfeed + 'item' + i, state);
        }
        else
        {
            flipDisplay('cat' + whichcat + 'feed' + whichfeed + 'item' + i);
        }
    }
}

// Changes the visibility of all items in a category
function flipAllArticlesInCat(state, whichcat)
{
    var i;
    for (i=0; i<numfeeds[whichcat]; i++)
    {
        flipArticle(state, whichcat, i);
    }
}

// Changes the visibility of all items on the page
function flipAllArticles(state)
{
    var i;
    for (i=0; i<numcats; i++)
    {
        flipAllArticlesInCat(state, i);
    }
}
-->
</script>
    <?
    }
    echo "</head>\n";
}

/**
 * Draw the HTML footer for the page.
 */
function drawFooter()
{
    ?>
<div class="version">$Id: index.php,v 1.56 2007/07/29 21:56:10 cyb0rg Exp $</div>

</body>
</html>
    <?
}

/**
 * Draws a single RSS item
 *
 * @param mixed $item The MagpieRSS item object
 * @param int $catnum The current category number (needed for Javascript functions)
 * @param int $feednum The current feed number (needed for Javascript functions)
 * @param int $itemnum The current item number (needed for Javascript functions)
 * @global Zort $zort
 */
function drawRssItem($item, $catnum, $feednum, $itemnum)
{
    // I really hate all these "global" declarations all over the place
    global $zort;

    $content = '';
    $contentname = '';
    $possibletypes = array('content:encoded', 'description', 'atom_content');
    foreach ($possibletypes as $type)
    {
        if (strpos($type, ':') !== false)
        {
            $halves = explode(':', $type, 2);
            if (array_key_exists($halves[0], $item) and
                array_key_exists($halves[1], $item[$halves[0]]))
            {
                $contentname = $type;
                $content = $item[$halves[0]][$halves[1]];
                break;
            }
        }
        else
        {
            if (array_key_exists($type, $item) and $item[$type] != '')
            {
                $contentname = $type;
                $content = $item[$type];
                break;
            }
        }
    }
    if ($content != '')
    {
        echo "<img src=\"plus.png\" onClick=\"flipDisplay('cat$catnum" . "feed$feednum" . "item$itemnum')\" id=\"cat$catnum" . "feed$feednum" . "item$itemnum" . "img\" class=\"link\">&nbsp;";
    }
    // This section depends on having a patched MagpieRSS which supports
    // loading "enclosure" information.  It looks like MagpieRSS is
    // undergoing a rewrite for 2.0, but that's probably a little ways off,
    // and probably means that the 1.x branch won't see much more activity.
    // So anyway, here it is.  Using an unpatched MagpieRSS will simply never
    // evaluate to "true" here, so no worries if your version's unpatched.
    if (array_key_exists('_attrs', $item) and array_key_exists('enclosure', $item['_attrs']) and
        array_key_exists('type', $item['_attrs']['enclosure']) and
        array_key_exists('url', $item['_attrs']['enclosure']))
    {
        echo '<a href="' . $item['_attrs']['enclosure']['url'] . '"><img src="attach.png" border="0"></a>&nbsp;';
    }
    if (array_key_exists('link', $item) and $item['link'] != '')
    {
        echo "<a href=\"" . $item['link'] . "\">" . (array_key_exists('title', $item) ? $item['title'] : '') . "</a>&nbsp;";
    }
    else
    {
        if (array_key_exists('title', $item))
        {
            echo $item['title'];
        }
        echo '&nbsp;';
    }
    if (array_key_exists('date_timestamp', $item) and $item['date_timestamp'] != '')
    {
        echo "<font size=\"-1\"><strong>(" . date('r', $item['date_timestamp']) . ")</strong></font>\n";
    }
    echo "<p>\n";
    if ($content != '')
    {
        echo "<div style=\"display: none\" id=\"cat$catnum" . "feed$feednum" . "item$itemnum\">\n";
        echo "<div class=\"articletext\"><br>\n";
        if (strtoupper(substr($content, 0, 4)) == '<BR>')
        {
            $content = substr($content, 4);
        }

        // Output the actual content
        if ($zort->fixhtml and function_exists('tidy_clean_repair'))
        {
            // This should be the block used for PHP4, with PECL-Tidy installed
            tidy_parse_string($content);
            tidy_clean_repair();
            echo tidy_get_output();
        }
        elseif ($zort->fixhtml and function_exists('tidy_parse_string'))
        {
            // This should be the block used for PHP5, with --enable-tidy
            $tidy = tidy_parse_string($content);
            $tidy->cleanRepair();
            echo $tidy;
        }
        else
        {
            // This will just dump the content as-is
            echo $content;
        }
        echo "\n";
        echo "<div style=\"clear: both\">&nbsp;</div>\n";
        echo "</div>\n";
        echo "</div>\n";
    }
    echo "</p>\n";
}

/**
 * Draws a single RSS Feed
 *
 * @param int $feedcount Counter for each feed, used to draw the colors properly
 * @param mixed $feed The MagpieRSS feed object
 * @param int $catnum The current category number (used for Javascript functions)
 * @param int $feednum The current feed number (used for Javascript functions)
 * @global array $colors
 */
function drawRssFeed($feedcount, $feed, $catnum, $feednum)
{
    global $colors;

    // Get the actual Magpie object out of our own object
    $magpiefeed = $feed->data();

    echo "<div id=\"hcolor" . (($feedcount-1) % count($colors)) . "\">\n";
    echo "<strong>\n";
    
    if ($feed->is_valid())
    {
        // Figure out what date to show
        $moddate = '';
        $possibledates = array(
            $magpiefeed->items[0]['pubdate'],
            $magpiefeed->last_modified,
            $magpiefeed->channel['pubdate']
        );
        foreach ($possibledates as $possibledate)
        {
            if ($possibledate and $possibledate != '')
            {
                $moddate = $possibledate;
                break;
            }
        }
        if ($moddate != '')
        {
            $then = strtotime($moddate);
            if ($then != -1)
            {
                $diff = time() - $then;
                if ($diff >= 0)
                {
                    if ($diff > 2592000)
                    {
                        // I'm obviously flubbing this since there's not 30 days in
                        // every month.  I'm okay with that, though.
                        $intdiff = (int)($diff/2592000);
                        $engdiff = $intdiff . ' month';
                    }
                    elseif ($diff > 604800)
                    {
                        $intdiff = (int)($diff/604800);
                        $engdiff = $intdiff . ' week';
                    }
                    elseif ($diff > 86400)
                    {
                        // the "day" calculation is tricksier because people will
                        // expect the calculations to happen regardless of time
                        $intdiff = (int)((strtotime('today 23:59:59') - $then)/86400);
                        $engdiff = $intdiff . ' day';
                    }
                    elseif ($diff > 3600)
                    {
                        $intdiff = (int)($diff/3600);
                        $engdiff = $intdiff . ' hour';
                    }
                    elseif ($diff > 60)
                    {
                        $intdiff = (int)($diff/60);
                        $engdiff = $intdiff . ' minute';
                    }
                    else
                    {
                        $intdiff = $diff;
                        $engdiff = $intdiff . ' second';
                    }
                    if ($intdiff != 1)
                    {
                        $engdiff .= 's';
                    }
                    $engdiff .= ' ago';
                    echo "<span class=\"lastmodified\">" . $engdiff . "</span>\n";
                }
                else
                {
                    echo "<span class=\"lastmodified\">" . date('r', $then) . "</span>\n";
                }
            }
        }

        // Now start displaying things
        echo "<img src=\"wplus.png\" onClick=\"flipDisplay('cat$catnum" . "feed$feednum')\" id=\"cat$catnum" . "feed$feednum" . "img\" class=\"link\">&nbsp;";
        echo '<a class="title" href="' . $magpiefeed->channel['link'] . '">';
        if ($feed->overridetitle() == '')
        {
            echo $magpiefeed->channel['title'];
        }
        else
        {
            echo $feed->overridetitle();
        }
        echo "</a>\n";
        if ($magpiefeed->_magpie_error and $magpiefeed->_magpie_error != '')
        {
            echo '&nbsp;&nbsp;<em class="titleerror">(cached copy - ' . $magpiefeed->_magpie_error . ')</em>';
        }
    }
    else
    {
        echo '<span class="title">Error retrieving feed ';
        if ($feed->_title and $feed->_title != '')
        {
            print '"' . $feed->_title . '"';
        }
        else
        {
            print $feed->_url;
        }
        print ' - ' . $feed->error() . '</span>';
    }

    echo "</strong><br>\n";
    echo "</div>\n";
    echo "<div style=\"display: none\" id=\"cat$catnum" . "feed$feednum\">\n";

    if ($feed->is_valid())
    {
        echo "<div id=\"bcolor" . (($feedcount-1) % count($colors)) . "\">\n";
        echo "<ul>\n";
        $disparticles = 0;
        foreach ($magpiefeed->items as $item)
        {
            if ((array_key_exists('description', $item) and $item['description'] != '')
                or (array_key_exists('atom_content', $item) and $item['atom_content'] != ''))
            {
                $disparticles = 1;
                break;
            }
        }
        echo "<br>\n";
        if ($disparticles)
        {
            echo "<div class=\"smalltext\">(articles <span class=\"link\" onClick=\"flipArticle(null, $catnum, $feednum);\">toggle</span> | <span class=\"link\" onClick=\"flipArticle('on', $catnum, $feednum);\">on</span> | <span class=\"link\" onClick=\"flipArticle('off', $catnum, $feednum);\">off</span>)</div><p>\n";
        }
        $i = -1;
        foreach ($magpiefeed->items as $item)
        {
            $i++;
            drawRssItem($item, $catnum, $feednum, $i);
        }
        echo "&nbsp;\n";
        echo "</ul>\n";
        echo "</div>\n";
    }

    echo "</div>\n";
    echo "<p></p>\n";
}

/**
 * Draw a single RSS Category
 *
 * @param string $cat The category name
 * @param int $curtotal Current total number of Feeds displayed (used to draw color correctly)
 * @param array $feeds The array of feeds belonging to this category
 * @param int $catnum The current category number (used for Javascript functions)
 * @global bool $usingopera
 * @return int The total number of feeds drawn (used to draw color correctly)
 */
function drawRssCat($cat, $curtotal, $feeds, $catnum)
{
    global $usingopera;
    $mytotal = $curtotal;
    echo "<div class=\"cattitle\">\n";
    echo "<strong><img src=\"minus.png\" onClick=\"flipDisplay('cat$catnum')\" id=\"cat$catnum" . "img\" class=\"link\">&nbsp;";
    echo "$cat</strong><br>\n";
    echo "</div>\n";
    echo "<div ";
    if (!$usingopera)
    {
        print "style=\"display: inline\" ";
    }
    print "id=\"cat$catnum\">\n";
    echo "<ul>\n";
    echo "<div class=\"smalltext\">\n";
    echo "(feeds <span class=\"link\" onClick=\"flipFeed(null, $catnum);\">toggle</span> | <span class=\"link\" onClick=\"flipFeed('on', $catnum);\">on</span> | <span class=\"link\" onClick=\"flipFeed('off', $catnum);\">off</span>)";
    echo "<br>\n";
    echo "(articles <span class=\"link\" onClick=\"flipAllArticlesInCat(null, $catnum);\">toggle</span> | <span class=\"link\" onClick=\"flipAllArticlesInCat('on', $catnum);\">on</span> | <span class=\"link\" onClick=\"flipAllArticlesInCat('off', $catnum);\">off</span>)";
    echo "</div><p></p>\n";
    for ($i=0; $i<count($feeds); $i++)
    {
        $mytotal++;
        $rss = $feeds[$i];
        drawRssFeed($mytotal, $rss, $catnum, $i);
    }
    echo "</ul>\n";
    echo "</div>\n";
    echo "<p></p>\n";
    return $mytotal;
}

/**
 * Draw the whole Zort page (just the content, not headers and footers)
 *
 * @param array $cats The categories to show in the page
 * @param array $rsses The array of RSSes to display, arranged by category
 * @global Zort $zort
 */
function drawRssPage($cats, $rsses)
{
    global $zort;
    $total = 0;

    echo "<div class=\"smalltext\">\n";
    echo '<a href="http://zort.sf.net/">Zort</a> v' . $zort->version . "<br>\n";
    if (count($rsses) > 1)
    {
        echo "categories: <span class=\"link\" onClick=\"flipAllCats();\">toggle</span> | <span class=\"link\" onClick=\"flipAllCats('on');\">on</span> | <span class=\"link\" onClick=\"flipAllCats('off');\">off</span>\n";
        echo "<br>\n";
    }
    echo "feeds: <span class=\"link\" onClick=\"flipAllFeeds();\">toggle</span> | <span class=\"link\" onClick=\"flipAllFeeds('on');\">on</span> | <span class=\"link\" onClick=\"flipAllFeeds('off');\">off</span>\n";
    echo "<br>\n";
    echo "articles: <span class=\"link\" onClick=\"flipAllArticles();\">toggle</span> | <span class=\"link\" onClick=\"flipAllArticles('on');\">on</span> | <span class=\"link\" onClick=\"flipAllArticles('off');\">off</span>\n";
    echo "</div>\n";
    echo "<p>\n";

    if (count($rsses) > 1)
    {
        for ($i=0; $i<count($rsses); $i++)
        {
            $total = drawRssCat($cats[$i], $total, $rsses[$cats[$i]], $i);
        }
    }
    elseif (count($rsses) == 1)
    {
        $feeds = $rsses[$cats[0]];
        for ($i=0; $i<count($rsses[$cats[0]]); $i++)
        {
            $total++;
            $rss = $feeds[$i];
            drawRssFeed($total, $rss, 0, $i);
        }
    }
    else
    {
        echo "Warning: no RSS categories defined<br>\n";
    }
}

/**
 * Draws a list of possible pages, if more than one are specified.
 *
 * @param array $pages An array of pages to be drawn
 * @param int $curidx Current page index (corresponds to our current place in the $pages array)
 */
function drawRssPageLinks($pages, $curidx)
{
    if (count($pages) > 1)
    {
        $i = 0;
        echo "<center>\n";
        echo "<div class=\"pagetitle\">" . $pages[$curidx][2] . "</div>\n";
        echo "<div class=\"smalltext\">\n";
        $todisplay = array();
        foreach($pages as $page)
        {
            if ($i != $curidx)
            {
                $todisplay[] = "<a href=\"" . $_SERVER['SCRIPT_NAME'] . "?rssidx=$i\">" . $page[2] . "</a>";
            }
            $i++;
        }
        print join(' | ', $todisplay);
        echo "</div>\n";
        echo "</center>\n";
        echo "<p></p>\n";
    }
}

/**
 * Sets up the default array of colors that we'll draw with.
 * @global Zort $zort
 */
function defaultColors()
{
    global $zort;
    $zort->color_add('#9c9', '#cf9');
    $zort->color_add('#69c', '#9cf');
    $zort->color_add('#933', '#c99');
    $zort->color_add('#993', '#cc9');
    $zort->color_add('#399', '#9cc');
    $zort->color_add('#939', '#e9e');
    $zort->color_add('#999', '#ddd');
}

/**
 * Actual program execution begins here.
 */

// First things first: check for required PHP functions
$functions = array('xml_parser_create' => 'XML Functions');
$needed = array();
foreach ($functions as $funcname => $option)
{
    if (!function_exists($funcname))
    {
        $needed[$funcname] = $option;
    }
}
if (count($needed) > 0)
{
    drawHeader('Needed PHP functions not found');
    print "<body>\n";
    print "<strong>Warning:</strong> The following PHP functions were not found.  Your PHP\n";
    print "installation needs to support these functions before Zort can be used.<p>\n";
    print '<table border="1" cellpadding="5" cellspacing="0"><tr><th>Function Name</th><th>Provided by</th></tr>';
    foreach ($needed as $funcname => $option)
    {
        print '<tr><td>' . $funcname . '</td><td>' . $option . "</td></tr>\n";
    }
    print "</table>\n";
    drawFooter();
    exit;
}

// Now make sure that our Magpie cache directory is writeable
if (!is_writable('./cache'))
{
    drawHeader('MagpieRSS Cache Directory Not Writable');
    print "<body>\n";
    print "<strong>Warning:</strong> The directory 'cache' needs to be writable in order for MagpieRSS's caching\n";
    print "to work properly.  Zort will refuse to run until the directory is given the proper permissions.<p>";
    drawFooter();
    exit;
}

// We require Magpie to be loaded *before* session_start, otherwise
// our session data may be Problematic.
require_once('magpierss/rss_fetch.inc');

// Start up a session
session_name('Zort');
session_start();

// Initialize the Zort object
$zort = new Zort();
$zort->color_reset();
defaultColors();

// Load in the user config
require_once('config.php');

// If the user invalidated $colors, re-populate the defaults
if (!is_array($colors) or count($colors) == 0)
{
    $zort->color_reset();
    defaultColors();
}

// Check for Opera - needed for a rendering fix
// Reported to Opera as bug #203218 - you can find some
// details about it at http://apocalyptech.com/opera/
// TODO: Find some way of not having to differentiate.
$usingopera = false;
if (array_key_exists('HTTP_USER_AGENT', $_SERVER) and
    strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false)
{
    $usingopera = true;
}

// Now grab the $pages array we used to have
$pages = $zort->getpages();

// Which set of feeds / categories will we use?
$rssidx = 0;
if (array_key_exists('rssidx', $_REQUEST) and $_REQUEST['rssidx'] != '')
{
    $rssidx = $_REQUEST['rssidx'];
}
$catstouse = $pages[$rssidx][0];
$feedstouse = $pages[$rssidx][1];

// See if we should show a loading page or not
$showloading = false;
if ($zort->showloadingpage)
{
    if (!array_key_exists('shownloading', $_REQUEST))
    {
        $showloading = true;
        drawHeader($zort->get_title() . ' - Loading Feeds', false);
        echo '<h3>' . $zort->get_title() . " - Loading Feeds</h3>\n";
    }
}

// Grab our RSS feeds if need be
$rsses = array();
if (ini_get('session.auto_start') != '1' and strtolower(ini_get('session.auto_start')) != 'yes' and
    $zort->showloadingpage and array_key_exists('shownloading', $_REQUEST) and array_key_exists('rss_obj', $_SESSION))
{
    // If we're supposed to show a loading page, and we HAVE already, and our
    // session var is present the way it should be, then just load from session.
    // Also don't attempt loading if session.auto_start is on, because we'll have
    // an invalid object then (because the necessary classes wouldn't get loaded
    // before the session, which causes Problems)
    $rsses = $_SESSION['rss_obj'];
    unset($_SESSION['rss_obj']);
}
else
{
    // ... otherwise load up the object
    $curlevel = error_reporting();
    error_reporting($curlevel ^ E_USER_WARNING);
    foreach ($catstouse as $cat)
    {
        if ($showloading)
        {
            print "Loading category $cat<br>\n";
            print "<ul>\n";
        }
        $rsses[$cat] = array();
        foreach ($feedstouse[$cat] as $feed)
        {
            if ($showloading)
            {
                if ($feed->overridetitle() == '')
                {
                    $title = $feed->get_url();
                }
                else
                {
                    $title = $feed->overridetitle();
                }
                print '<li>Loading <a href="' . $feed->get_url() . '">' . $title . "</a></li>\n";

                // Flush output so we see the status go by
                ob_flush();
                flush();
            }
            $feed->fetch();
            // If we're supposed to limit the number of feeds, do so
            if ($feed->is_valid())
            {
                $data = $feed->data();
                if (count($data->items) > $feed->maxitems())
                {
                    $data->items = array_slice($data->items, 0, $feed->maxitems());
                    $feed->set_data($data);
                }
            }
            $rsses[$cat][] = $feed;
        }
        if ($showloading)
        {
            print "</ul>\n";
        }
    }
    error_reporting($curlevel);
}

if ($showloading)
{
    // Store the information in the session, unless we're already past the
    // loading screen (this will handle page reloads, etc)
    if ($showloading)
    {
        $_SESSION['rss_obj'] = $rsses;
    }

    // Now do the redirect
    $newurl = $_SERVER['REQUEST_URI'];
    if (array_key_exists('QUERY_STRING', $_SERVER) and $_SERVER['QUERY_STRING'] and $_SERVER['QUERY_STRING'] != '')
    {
        $newurl .= '&';
    }
    else
    {
        $newurl .= '?';
    }
    $newurl .= 'shownloading=1';
    ?>
(done!)<p>
If this page does not automatically redirect to the actual feeds, please <a href="<?=$newurl?>">click here</a> to go there
manually.<p>
    <?
    ob_flush();
    flush();
    ?>
<script type="text/javascript">
<!--
window.location = "<?=$newurl?>";
//-->
</script>
    <?
    drawFooter();
    exit;
}

// Figure out which title to set
$displaytitle = $zort->get_title();
if ($pages[$rssidx][2] != '' and $pages[$rssidx][2] != 'default')
{
    $displaytitle .= ' - ' . $pages[$rssidx][2];
}

// Now display the page
drawHeader($displaytitle);
print "<body>\n";
drawRssPageLinks($pages, $rssidx);
drawRssPage($catstouse, $rsses);
drawFooter();

?>
Return current item: Zort