Aquarionics

/home/a/aquarion/sites/www.aquarionics.com/epistula/include/class.php

All my code (That is, anything not in the "Others" list on the right) is BSD licenced.

You can also view this page as text/plain or colour-coded source


<?PHP
/*******************************************************************************
    Classes
********************************************************************************

    The classes, including the display class (which is dreadfully sick),
    the syndication formats and other stuff

    TODO: use a templating system, for fucks sake

    $Id: class.php,v 1.4 2004/08/17 19:59:35 aquarion Exp $

    $log$

*******************************************************************************/

include("classes/html.class.php");

class Epistula {
    ##--------------+
    #| Field        |
    #+--------------+
    #| id           |
    #| title        |
    #| date_created |
    #| date_edited  |
    #| author       |
    #| content      |
    #+--------------#
    var $id;
    var $title;
    var $date_created;
    var $author;
    var $content;
    var $description;
    var $location;
    var $format;
    var $cats;
    var $fields;
    var $actions;
    var $filters;
    var $trackbacks;
    var $debug;

    var $_table;
    var $_type;

    function Epistula($id=0) {
        global $_EP;

        $this->_type = $this->_table = get_class($this);

        #$this->cats = array();
        $this->fields = array();
        $this->trackbacks = array();
        $this->id = 0;

        if (isset($_COOKIE['location'])){
            $this->location = $_COOKIE['location'];
        } else {
            $this->location = $_EP['location'];
        }
        $this->date_created = "NOW()";
        $this->date_edited = "NOW()";
        $this->author = 0;
        $this->format = "textile";
        $this->status = "0";
        $this->debug = array("Created ".$this." object");

        if ($id != 0){
            $this->loadData($id);
        }
        
        // Set up local category cache
        $this->debug[] = "Set up local category cache";
        $q = "select * from category order by name";
        $res = safequery($q, false); // don't panic on fail.
        while ($feline = mysql_fetch_assoc($res)){
            $feline['oldstatus'] = false;
            $feline['newstatus'] = false;
            $this->cats[$feline['id']] = $feline;
        }

        // End

        $fields = mysql_list_fields($_EP['dbname'], get_class($this));
        $columns = mysql_num_fields($fields);
        for ($i = 0; $i < $columns; $i++) {
            $this->fields[] = array(mysql_field_name($fields, $i), mysql_field_type($fields, $i));
        }
        $actions = array();
        $filters = array();
        $this->setActionsFilters();
    }

    
    /**
        void function loadData (int id)
    
        Load the data from id $id into the object
    */
    function loadData($id){
        $this->debug[] = "Loading data from id ".$id;
        $res = safequery("Select *, unix_timestamp(date_created) as created_epoch from ".get_class($this)." where id = ".$id);
        $idexist = mysql_num_rows($res);
        if ($idexist != 0){
            $row = mysql_fetch_assoc($res);
            foreach ($row as $key=>$value){
                $this->$key = $value;
            }
            $cats = getCat(get_class($this),$id);//full version of all cats.
            foreach ($cats as $cat){
                $this->cats[$cat['id']]['oldstatus'] = true;
                $this->cats[$cat['id']]['newstatus'] = true;
            }
        } else { // Attempt to get id broke. Table or ID doesn't exist
            $this->debug[] = "** Couldn't load ".get_class($this)."-".$id." from DB, object is empty.";
            return false;
        }
    } // end func load Data

    function setActionsFilters(){
        $this->debug[] = "Set defaults for actions &amp; filters";
        $actions = array(
            array("pingback" => true),
            array("pingThings" => true)
        );
        $filters = array(
            array("html" => false),
            array("tagify" => true)
        );
    }

    function validate(){
        $this->debug[] = "Validating...";
        $required = array("title", "author", "content");
        foreach ($required as $check){
            if (isset($this->$required)){
                $error .= ucwords($required)." cannot be empty\n";
            }
        }
        $catcount = 0;
        foreach($this->cats as $cat){
            if ($cat['newstatus']){
                $catcount++;
            }
        }
        if ($catcount == 0){
            $error .= "Must set at least one category";
        }
        #print_r($this);
        if (count($error) == 0){
            $this->debug[] = "Validation sucessful";
            return array(true,$error);
        } else {
            $this->debug[] = "Validation failed.";
            return array(false,$error);
        }
    }

    function save($notreally=false){


        if ($this->title == ""){
            $this->title = "Untitled";
        }

        $this->debug[] = "Saving object to database";
        $this->content = addslashes($this->doFilters(stripslashes($this->content)));
        $this->description = addslashes($this->doFilters(stripslashes($this->description)));
        $table = get_class($this);
        $validate = $this->validate();
        
        if (!$validate[0]){
            $this->debug[] = $validate[1];
            return array(false,$validate[1]);
        } elseif($this->id != 0) {
            $this->debug[] = "ID set, creating update query";
            $query = "update ".$table." set ";
            $index_check = count($this->fields)-1;
            $index_count = 0;
            foreach ($this->fields as $field){
                if ($field[0] == "date_created" ||  $field[0] == "date_edited" ||  $field[0] == "id") {
                    true;
                } else {
                    if ($field[1] == "blob" || $field[1] == "string"){
                        $query .= $field[0]." = \"".$this->$field[0]."\"";
                    } else {
                        $query .= $field[0]." = ".$this->$field[0];
                    }
                    if ($index_count != $index_check){
                        $query .= ", ";
                    }                        
                }
                $index_count++;
            }
            $query .= " where id=".$this->id;
            #$this->debug[] = "Build query: ".$query;
            if ($notreally){
                $this->debug[] = "Not saved to DB, as requested";
                $this->saveCats("notreally");
                $return = $query;
            } else {
                $this->debug[] = "Saving to DB...";
                #$this->debug[] = "<pre>".print_r_to_var($this)."</pre>";
                safequery($query, false);
                $this->saveCats();
                $this->doActions();
                $delc_log = deleteCache($this->id,$table);
                $this->debug[] = "Deleting Cache Files";
                #foreach ($delc_log as $entry) {
                #    $this->debug[] = $entry;
                #}
                $return = true;
            }
        } else {
            $this->debug[] = "ID not set, creating insert query";
            $query = "insert into ".$table." (";

            $fields = "";
            $values = "";

            $index_check = count($this->fields)-1;
            $index_count = 0;
            foreach ($this->fields as $field){
                $fields .= $field[0];
                if ($field[1] == "blob" || $field[1] == "string"){
                    $values .="\"".$this->$field[0]."\"";
                } else {
                    $values .=$this->$field[0];
                }
                if ($index_count != $index_check){
                    $fields .= ", ";
                    $values .= ", ";
                }
                $index_count++;
            }
            $query .= $fields.") values (".$values.")";
            #$this->debug[] = "Created query ".$query;
            if ($notreally){
                $this->debug[] = "Not saved to DB, as requested";
                $return = $query."\n";
                $this->debug[] = $query."\n";
                $return .= $this->saveCats("notreally");
            } else {
                $this->debug[] = "Saving to DB...";
                safequery($query, true);
                $this->id = mysql_insert_id();
                $this->saveCats();
                $this->doActions();
                $delc_log = deleteCache($this->id,$table);
                foreach ($delc_log as $entry) {
                    $this->debug[] = $entry;
                }
            }
        }
        return $return;
    }

    function saveCats($notreally=false){
        $this->debug[] = "Saving categories to db...";
        foreach($this->cats as $cat){
            if ($cat['newstatus'] != $cat['oldstatus']){
                if ($cat['newstatus']){ // if it's now categorised as that
                    $query = "insert into cat_links (page_id, page_type, cat_id)"
                            ." values (".$this->id.", \"".get_class($this)."\", ".$cat['id'].")";
                    $this->debug[] = "Added object to ".$cat['name'];
                } else {
                    $query = "delete from cat_links where "
                            ." page_type = \"".get_class($this)."\" and page_id = ".$this->id;
                    $this->debug[] = "Deleted object from ".$cat['name'];
                }
                if ($notreally){
                    return $query;
                } else {
                    safequery($query, false);
                }
            }
        }
    }

    function remove(){
        $item = get_class($this);
        $id = $this->id;
        $queries = array(
            "delete from $item where id = $id",
            "delete from cat_links where page_type = \"$item\" and page_id = \"$id\"",
            "delete from attachment where page_type = \"$item\" and page_id = \"$id\"",
            "delete from crossreference where attachfromtype = \"$item\" and attachfromid = \"$id\"",
            "delete from crossreference where attachtotype = \"$item\" and attachtoid = \"$id\"",
            "delete from comment where thread_id = \"".$item."-".$id."\"");

        deleteCache($id,$item);
        foreach ($queries as $query){
            safequery($query);
        }
    }

    function doFilters($content){
        $this->debug[] = "Applying filters:";

        if ($this->filters['htmlize'] == true) {
            $content  = ereg_replace("[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]","<a href=\"\\0\" class=\"commentlink\">\\0</a>", $content);
            $content = nl2br($content);
        }
        if ($this->filters['tagify'] == true) {
            $content = tagifythis($content);
        }

        return $content;
    }

    function doActions(){
        global $_EP;
        $this->debug[] = "Doing actions:";
        if ($this->actions['pingThings'] == true) {
            $return = pingServices();
            foreach ($return as $name => $ping){
                $this->debug[] = "Sending ping to ".$name;
                $this->debug[] = $ping[1];
            }
        }
        

        if ($this->actions['pingBack']) {
            $this->debug[] = "Sending pingbacks - ".date("H:i");
            
            $content = process($this->content, $this->format);

            $links = liftLinks(stripslashes($this->content));
            pingback($links, get_class($this), $this->id, true);
        }
        $this->debug[] = "Done actions - ".date("H:i");;
    }

    
    function display($path){
        
    }

}

class journal extends Epistula {

}

class article extends Epistula {
    var $status;
}

class writing extends Epistula {
}

class moblog extends Epistula {

}

class twitter extends Epistula {

}


class item extends Epistula { // Obsolete

}


/**
    Context of the class
    Short description.
*/
class syndication
{
        var $title;
        var $url;
        var $description;
        var $author;
        var $email;
        var $items;

        
        /**
            void function syndication (void)
        
            Constructor for Syndication Class
        */
        function syndication()
        {
            global $_EP;
            $this->title = $_EP['book'];
            $this->url = $_EP['url'];
            $this->description = "Descriptionless Item";
            $this->author = "Aquarion";
            $this->email = $_EP['admin'];
            $this->items = array();
            
        } // end func

        
        /**
            void function (void)
        
            Short description. 
        */
        function build()
        {
            $out = "Syndication for ".$this->author." (".$this->email."), who stupidly asked for a syndication without a corresponding class.\n";
            $out .= "Lets all laugh at ".$this->author.", shall we? and not read.".$this->title." at ".$this->url."\n";
            return $out;
        } // end func
} // end class

/*
    Necho Cut 1, 2003-07-03
*/

class necho  extends syndication
{
    function build()
    {
//            global $_EP;
//            $this->title = $_EP['book'];
//            $this->url = $_EP['url'];
//            $this->description = "Descriptionless Item";
//            $this->author = "Aquarion";
//            $this->email = $_EP['admin'];
//            $this->items = array();
    global $_EP;
    $dateformat = "Y-m-d\TH:i:00O";
    $out = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n";
    $out .= "<feed xmlns=\"http://example.com/newformat#\" xmlns:ent=\"http://www.purl.org/NET/ENT/1.0/\" version=\"1.0\">\n"
      ."<title>".$_EP['book']."</title>\n"
      ."<subtitle>".$this->description."</subtitle>\n"
      ."<link>".$_EP['url']."</link>\n"
      
      ."<modified>".date($dateformat)."</modified>\n";

        foreach ($this->items as $item){
            # title url id content type epoch
            if ($item['link']){
                $guid = $item['link'];
            } else {
                $guid = getPermalink($item['epistulatype'],$item['id']);
            }
            $trackback = $_EP['url']."/trackback/".$item['epistulatype']."/".$item['id'];
            #$comments = count(get_comments_array($item['epistulatype']."-".$item['id']));
            $categories = getCat($item['epistulatype'],$item['id']);

            $text = process($item['content'], $item['format']);
            if ($item['description'] == ""){
                $desc = htmlspecialchars(break_string(strtr($text,"’","'"),400),ENT_NOQUOTES);
            } else {
                $desc = strip_tags(process($item['description'], $item['format']));
            }

            $out .= "\n<entry>\n"
                 ."\t<title>".htmlspecialchars($item['title'],ENT_NOQUOTES)."</title>\n"
                 ."\t<link>".$guid."</link>\n"
                ."\t<id>".$_EP['url']."/".$item['epistulatype']."-".$item['id']."</id>\n"

                # ."\t<comments>".$guid."</comments>\n"
                 ."\t<summary>".$desc."</summary>\n"

                ."\t<created>".date($dateformat,$item['epoch'])."</created>"
                ."\t<issued>".date($dateformat,$item['epoch'])."</issued>"
                ."\t<modified>".date($dateformat,$item['update_epoch'])."</modified>"

                . "\t<content type=\"text/html\"><![CDATA[".strtr($text,"’","'")."]]></content>\n";

                foreach ($item['attachments'] as $attachment){
                    $out .= "<content type=\"".$attachment['mimetype']." "
                        ."src=\"".$_EP['url']."/".$attachment['file']."\" "
                #        ."length=\"".$attachment['size']."\" "
                        ."\"/>\n";
                }


                foreach ($categories as $cat){
                        $out .= "\t<ent:topic>".$cat['name']."</ent:topic>\n";
                }

        #    $out .="\t<slash:comments>".$comments."</slash:comments>\n"
        #         ."\t<slash:section>".$item['epistulatype']."</slash:section>\n"
        #         ."\t<trackback:ping>".$trackback."</trackback:ping>\n"
        #         ."</item>\n";
            
            $out .="</entry>\n";

        }      
      
    $out .= "</feed>";

    return $out;
    }
}


/**
    Context of the class
    Short description.
*/
class rss2 extends syndication
{
    
    /**
        string function build (void)
    
        Returns a valid RSS2 feed.
    */
    function build()
    {
        if (PHP_VERSION >= 5){
            $dateformat = "c";
            $tzd = ""; // Don't need TimeZone Data
        } else {
            $dateformat = "Y-m-d\TH:i:00";
            $mod = date("Z")%(60*60);
            if ($mod != 0){
                $semi = ":00";
            } else {
                $semi = ":30";
            }
            $tzd = sprintf("%+03d",(date("Z")/(60*60))).$semi;
        }
        // <dc:date>2004-09-15T11:10:00+0000</dc:date>
        //          2002-10-02T10:00:00-05:00
        global $_EP;
            $out ="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
                 ."<rss version=\"2.0\" \n"
                 ."  xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n"
                 ."  xmlns:sy=\"http://purl.org/rss/1.0/modules/syndication/\"\n"
                 ."  xmlns:admin=\"http://webns.net/mvcb/\"\n"
                 ."  xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"
                 ."  xmlns:content=\"http://purl.org/rss/1.0/modules/content/\"\n"
                 ."  xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n"
                 ."  xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\">\n"
                 ."<channel>\n"
                 ."<title>".$this->title."</title>\n"
                 ."<link>".$this->url."</link>\n"
                 ."<description>".htmlspecialchars($this->description)."</description>\n"
                 ."<dc:language>en-gb</dc:language>\n"
                 ."<dc:creator>".$this->author." (".$this->email.")</dc:creator>\n"
                 ."<dc:rights>Copyright ".date("Y")." ".$this->author."</dc:rights>\n"
                 ."<dc:date>".date($dateformat).$tzd."</dc:date>\n"

                 ."<admin:generatorAgent rdf:resource=\"http://www.aquarionics.com/epistula/?v=".$_EP['version']."\" />\n"
                 ."<admin:errorReportsTo rdf:resource=\"mailto:".$_EP['admin']."\"/>\n"
                 ."<sy:updatePeriod>daily</sy:updatePeriod>\n"
                 ."<sy:updateFrequency>8</sy:updateFrequency>\n"
                 ."<sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>\n";

            foreach ($this->items as $item){
            # title url id content type epoch
            if ($item['link']){
                $guid = $item['link'];
            } else {
                $guid = getPermalink($item['epistulatype'],$item['id']);
            }
            $trackback = $_EP['url']."/trackback/".$item['epistulatype']."/".$item['id'];
            $comments = count(get_comments_array($item['epistulatype']."-".$item['id']));
            $categories = getCat($item['epistulatype'],$item['id']);


            $text = process($item['content'], $item['format']);
            if ($item['description'] == ""){
                $desc = htmlspecialchars(break_string(strtr($text,"’","'"),400),ENT_NOQUOTES);
            } else {
                $desc = htmlspecialchars(strip_tags(process($item['description'], $item['format'])));
            }

            if ($item['display'] == "description"){
                $text = $desc;
            }

            $out .="<item>\n"
                 ."\t<title>".htmlspecialchars($item['title'],ENT_NOQUOTES)."</title>\n"
                 ."\t<link>".$guid."</link>\n"
                 ."\t<comments>".$guid."</comments>\n"
                 ."\t<description>".$desc."</description>\n"
                 ."\t<guid isPermaLink=\"true\">".$guid."</guid>\n";
            $out .= "\t<content:encoded><![CDATA[".strtr($text    ,"’","'")."]]></content:encoded>\n"
                 ."\t<dc:date>".date($dateformat,$item['epoch']).$tzd."</dc:date>\n";
                foreach ($categories as $cat){
                        $out .= "\t<dc:subject>".$cat['name']."</dc:subject>\n";
                }
                foreach ($item['attachments'] as $attachment){
                    $out .= "<enclosure "
                        ."url=\"".$_EP['url']."/".$attachment['file']."\" "
                        ."length=\"".$attachment['size']."\" "
                        ."type=\"".$attachment['mimetype']."\"/>\n";
                }

            $out .="\t<slash:comments>".$comments."</slash:comments>\n"
                 ."\t<slash:section>".$item['epistulatype']."</slash:section>\n"
                 ."\t<trackback:ping>".$trackback."</trackback:ping>\n"
                 ."</item>\n";

            }
            $out .= "</channel>\n"
                ."</rss>";
            return $out;
    } // end func
} // end class


/**
    Context of the class
    Short description.
*/
class rss extends syndication
{
    
    /**
        void function build (void)
    
        Create and return RSS feed. 
    */
    function build()
    {
        global $_EP;
        $out ="<?xml version=\"1.0\"?>\n"
             ."<?xml-stylesheet type=\"text/xsl\" href=\"/assets/rss.xsl\"?>"
             ."<rss version=\"0.92\">\n"
             ."<channel>\n"
             ."<title>".$this->title."</title>\n"
             ."<link>".$this->url."</link>\n"
             ."<description>".$this->description."</description>\n"
             ."<language>en-gb</language>\n"
             ."<managingEditor>".$this->author." (".$this->email.")</managingEditor>\n"
             ."<webMaster>Site Admin (".$_EP['admin'].")</webMaster>\n"
             ."<lastBuildDate>".date("D, d M Y H:i:00 O")."</lastBuildDate>\n" # Fri, 13 Apr 2001 19:23:02 GMT
             ."<docs>http://backend.userland.com/rss092</docs>\n";

        foreach ($this->items as $item){
        # title url id content type epoch
        #$guid = $_EP['url']."/".$item['epistulatype']."/id/".$item['id'];
        if ($item['link']){
            $guid = $item['link'];
        } else {
            $guid = getPermalink($item['epistulatype'],$item['id']);
        }
        $text = process($item['content'], $item['format']);
        if ($item['description'] == ""){
            $desc = htmlspecialchars(break_string(strtr($text,"’","'"),400),ENT_NOQUOTES);
        } else {
            $desc = strip_tags(process($item['description'], $item['format']));
        }
        $out .="<item>\n"
             ."\t<title>".htmlspecialchars($item['title'],ENT_NOQUOTES)."</title>\n"
             ."\t<link>".$guid."</link>\n"
             ."\t<description>".$desc."</description>\n";
             if (is_array($item['attachments'])){
            foreach ($item['attachments'] as $attachment){
                $out .= "<enclosure "
                            ."url=\"".$_EP['url']."/".$attachment['file']."\" "
                            ."length=\"".$attachment['size']."\" "
                            ."type=\"".$attachment['mimetype']."\"/>\n";
            }
             }
            $out .= "</item>\n";

        }
        $out .= "</channel>\n"
            ."</rss>";
        
        return $out;
    } // end func
} // end class


/**
    Context of the class
    Short description.
*/
class cdf extends syndication // Microsoft Common Data Format.
/*
XML ENCODING="UTF-8" VERSION="1.0" 
<CHANNEL HREF="http://domain/folder/pageOne.extension"
  BASE="http://domain/folder/"
  LASTMOD="1998-11-05T22:12"
  PRECACHE="YES"
  LEVEL="0">
    <TITLE>Title of your Channel</TITLE>
    <ABSTRACT>Synopsis of your channel's contents.</ABSTRACT>
    <SCHEDULE>
      <INTERVALTIME DAY="14"/>
    </SCHEDULE>
    <LOGO HREF="wideChannelLogo.gif" STYLE="IMAGE-WIDE"/>
    <LOGO HREF="imageChannelLogo.gif" STYLE="IMAGE"/>
    <LOGO HREF="iconChannelLogo.gif" STYLE="ICON"/>
    <ITEM HREF="pageTwo.extension"
      LASTMOD="1998-11-05T22:12"
      PRECACHE="YES"
      LEVEL="1">
        <TITLE>Page Two's Title</TITLE>
        <ABSTRACT>Synopsis of Page Two's contents.</ABSTRACT>
        <LOGO HREF="pageTwoLogo.gif" STYLE="IMAGE"/>
        <LOGO HREF="pageTwoLogo.gif" STYLE="ICON"/>
    </ITEM>
</CHANNEL>
*/
{
    
    /**
        void function (void)
    
        Short description. 
    */
    function build()
    {
        global $_EP;
        $out ="<?xml version=\"1.0\"?>\n"
            ."<CHANNEL HREF=\"".$this->url."\" "
            ."BASE=\"".$this->url."\" "
            ."LASTMOD=\"".date("Y-m-d\Th:i")."\" "
            ."PRECACHE=\"YES\" "
            ."LEVEL=\"0\">\n"
            ."\t<TITLE>".$this->title."</TITLE>\n"
            ."\t<ABSTRACT>".$this->description."</ABSTRACT>\n"
            ."\t<SCHEDULE>\n"
            ."\t\t<INTERVALTIME HOUR=\"1\"/>\n"
            ."\t</SCHEDULE>\n";
        foreach ($this->items as $item){
        # title url id content type epoch
        #$guid = $_EP['url']."/".$item['epistulatype']."/id/".$item['id'];
        if ($item['link']){
            $guid = $item['link'];
        } else {
            $guid = getPermalink($item['epistulatype'],$item['id']);
        }
        $text = process($item['content'], $item['format']);
        if ($item['description'] == ""){
            $desc = strtr(break_string($text,400), "ãäåçèéêëìíîïðñòóôõö÷øùúûüýêë’", "aaaceeeeiiiionooooo/ouuuuyee'");
        } else {
            $desc = strip_tags(process($item['description'], $item['format']));
        }
        $desc = htmlspecialchars(strtr($desc,"’","'"),ENT_NOQUOTES);
        $title = htmlspecialchars(strtr($item['title'],"’","'"),ENT_NOQUOTES);

        $out .="\t<ITEM href=\"".$guid."\" "
        ."LASTMOD=\"".date("Y-m-d\Th:i",$item['epoch'])."\" "
        ."PRECACHE=\"YES\" "
        ."LEVEL=\"0\">\n"
             ."\t\t<TITLE>".$title."</TITLE>\n"
             ."\t\t<ABSTRACT>".$desc."</ABSTRACT>\n";
            $out .= "\t</ITEM>\n";

        }
        $out .= "</CHANNEL>\n";
        
        return $out;
    } // end func
} // end class


/**
    Context of the class
    Short description.
*/
class esf extends syndication
{
    
    /**
        void function (void)
    
        Short description. 
    */
    function build()
    {
        global $_EP;
        $out ="#".$this->title." Newsfeed, in Episula Syndication Feed format (ESF)\n"
             ."#http://www.aquarionics.com/nodes/index.php?name=esf\n"
             ."title\t".$this->title."\n"
             ."contact\t".$this->email." (".$this->author.")\n"
             ."link\t".$this->url."\n\n";

        foreach ($this->items as $item){
        # title url id content type epoch
        if ($item['link']){
            $guid = $item['link'];
        } else {
            $guid = getPermalink($item['epistulatype'],$item['id']);
        }
        $out .=$item['epoch']."\t"
             .$item['title']."\t"
             .$guid."\t\n";
        }
        
        return $out;
    } // end func
} // end class

/*

// The great generic form creation thing. Started at 3am 10/01/2003

class form{
    var $action;
    var $method;
    var $name;
    var $items;
    var $title;

    function form($name = "form",$method = "post" ,$action=$_SERVER['PHP_SELF']){
        $this->name=$name;
        $this->method=$method;
        $this->action=$action;
        $this->action=array();
        $this->title=false;        
    }
    
    function buildHtml(){

    // Buttons

    submit
    reset
    
    // Checkboxen
    label name checked

    r
        
    }

}*/

/* 
     Spelchecker server code by Simon Willison, 
     http://simon.incutio.com/archive/2003/03/18/#phpAndJavascriptSpellChecker 
*/


class SpellChecker {
    var $command;
    var $text;
    var $errors = array();
    function SpellChecker($command = 'ispell') {